Assume you need to access data on SharePoint server. The information you need consists of a batch of similar items, for example, properties (like name) of users having their ID from a specific array, or the title of sites having their URL from an array as well. In the case of users (or other entities represented via list items) you could use CAML (see my former post for a similar, simple JSCOM example), although the query itself would be rather complex after a few dozens of items, however, other cases (like site names) might raise more serious issues.
You could send the requests consecutively, sending the next request only after you received the response for the former one, or you can send a set of asynchronous requests one after the other, and then process the responses parallel. I found neither of these options to be ideal. On one side, the high number of roundtrips between the client and server won’t help performance, on the other side, synchronizing requests and responses (have we received all the responses for our requests?) could be a nightmare.
Instead of these ones, we can implement a solution, where we cumulate all of the requests into a single context, then send the query at once, and process the single response.
Below I provide an example of this implementation for the managed client object model:
- List<int> lookupids = new List<int> { 19, 23, 32 };
- List<ListItem> userInfos = new List<ListItem>();
- using (ClientContext clientContext = new ClientContext("http://yoursharepointsite"))
- {
- lookupids.ForEach(id =>
- {
- ListItem userInfo = clientContext.Web.SiteUserInfoList.GetItemById(id);
- userInfos.Add(userInfo);
- clientContext.Load(userInfo);
- });
- clientContext.ExecuteQuery();
- IEnumerable<string> userEmails = userInfos.Select(userInfo => userInfo["EMail"].ToString());
- Console.WriteLine(String.Join(", ", userEmails.ToArray()));
- }
and the JavaScript version as well:
- <script type="text/javascript">
- var siteUrl = '/';
- var userInfos;
- function retrieveUsers() {
- var ids = [19, 23, 32];
- userInfos = new Array();
- var clientContext = new SP.ClientContext(siteUrl);
- var web = clientContext.get_web();
- var userList = web.get_siteUserInfoList();
- for(i=0; i<ids.length; i++) {
- var id = ids[i];
- var userInfo = userList.getItemById(id);
- clientContext.load(userInfo);
- userInfos[i] = userInfo;
- }
- clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
- }
- function onQuerySucceeded(sender, args) {
- var result = '';
- for(i=0; i<userInfos.length; i++)
- {
- var userInfo = userInfos[i];
- result += userInfo.get_item('Name') + ', ' + userInfo.get_item('Title') + ', ' + userInfo.get_item('EMail') + '\n';
- }
- alert(result);
- }
- function onQueryFailed(sender, args) {
- alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
- }
- ExecuteOrDelayUntilScriptLoaded(retrieveListItems, "sp.ribbon.js");
- </script>
Note: The key factor of this solution is that you subsequent queries must be independent from the responses of the former requests.
