Items are saved in jumbled bcoz I am using executeQueryAsync()
.How to make executeQueryAsync()
behave synchronously?
-
Javascript implementations typically perform work asynchronously for a good reason -- because they block UI interaction if implemented synchronously. I would suggest (and what Nadeem's answer depicts below) is using a specific method of waiting for asynchronous work to correctly complete (good), rather than synchronous program behavior (bad for Javascript in the browser)– John-MCommented Mar 17, 2015 at 17:06
2 Answers
You can use JavaScript call backs or Promises/deferreds to work with JavaScript client object model.
CallBack Example:
$(document).ready(function () {
//don't exectute any jsom until sp.js file has loaded.
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', prepareTables);
});
function prepareTables() {
getItemsWithCaml('External User Account Request',
function (camlItems) {
var listItemEnumerator = camlItems.getEnumerator();
while (listItemEnumerator.moveNext()) {
var listItem = listItemEnumerator.get_current();
console.log(listItem.get_item('Title'));
} console.log('Completed table prparation.');
},
function (sender, args) {
console.log('An error occured while retrieving list items:' + args.get_message());
});
}
function getItemsWithCaml(listTitle, success, error) {
var clientContext = new SP.ClientContext.get_current();
var list = clientContext.get_web().get_lists().getByTitle(listTitle);
var camlQuery = new SP.CamlQuery();
var camlItems = list.getItems(camlQuery);
clientContext.load(camlItems);
clientContext.executeQueryAsync(
function () {
success(camlItems);
},
error
);
};
Promises Example
$(document).ready(function () {
//don't exectute any jsom until sp.js file has loaded.
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', prepareTables);
});
function prepareTables() {
getItemsWithCaml('External User Account Request').then(
function (camlItems) {
var listItemEnumerator = camlItems.getEnumerator();
while (listItemEnumerator.moveNext()) {
var listItem = listItemEnumerator.get_current();
console.log(listItem.get_item('Title'));
} console.log('Completed table prparation.');
},
function (sender, args) {
console.log('An error occured while retrieving list items:' + args.get_message());
}
);
}
function getItemsWithCaml(listTitle) {
//use of $.Deferred in the executeQueryAsync delegate allows the consumer of this method to write 'syncronous like' code
var deferred = $.Deferred();
var clientContext = new SP.ClientContext.get_current();
var list = clientContext.get_web().get_lists().getByTitle(listTitle);
var camlQuery = new SP.CamlQuery();
var items = list.getItems(camlQuery);
clientContext.load(items);
clientContext.executeQueryAsync(
Function.createDelegate(this,
function () { deferred.resolve(items); }),
Function.createDelegate(this,
function (sender, args) { deferred.reject(sender, args); }));
return deferred.promise();
};
Check this for more information: http://www.sharepointnadeem.com/2014/10/sharepoint-using-deferredspromises-or.html
@NadeemYousuf: As you probably know, both callbacks and promises are only techniques to make a code that relies on asynchronous calls more readable by hiding the asynchronicity via advanced programming constructs. However, they do not make the calls syncronous, e.g. they do not block the calling thread until a reponse is received or a timeout occurs, and that is good so.
The JSCOM is designed to work async to not block the UI thread of the browser, and there is no way to call the executeQueryAsync method synchronously, AFAIK.
There are however methods to use the JSCOM in an async manner. Note that these methods are unsupported, as they rely on internal JavaScript methods / fields of the OM.
Here is an example for SP 2010 from my blog post. The single purpose of the code is to demonstrate that it is technically possible to send synchronous HTTP requests based on the request created via JSCOM. I strongly discourage anyone to use this code in a production environment.
var title = "";
try {
var context = SP.ClientContext.get_current();
var web = context.get_web();
var selectedListId = SP.ListOperation.Selection.getSelectedList();
var selectedListItem = web.get_lists().getById(selectedListId).getItemById(itemID);
context.load(selectedListItem, "Title");
// start hacking
var pendingRequest = context.get_pendingRequest();
var webRequest = pendingRequest.get_webRequest();
// get the request XML
var body = pendingRequest.$24_0().toString();
// get the URL of client.svc
var url = webRequest.get_url();
// "initialize" request
SP.ClientRequest.$1T(webRequest);
// we should add digest later to the request as an HTTP header (see below)
var digest = webRequest.get_headers()['X-RequestDigest'];
jQuery.ajax(
{
type: "POST",
data: body,
url: ctx.HttpRoot + url,
success: function (result) {
if (result.isOk != false) {
title = result[result.length – 1].Title;
}
},
headers: {
"x-requestdigest": digest
},
contentType: "application/x-www-form-urlencoded",
async: false
});
}
catch (e) {
alert("Error: " + e);
}
-
1probably I got carried away by the term "synchronously" in the question and used the same in my answer. Thanks for pointing out that promises/callback don't actually make the calls synchronous. +1, cheers! Commented Oct 27, 2016 at 10:44