One of the common problems with using the SharePoint client object model is the asynchronous nature of the object property calls. For example, if I want to retrieve a current user’s name, I would run code something like this:
context = new SP.ClientContext.get_current();
web = context.get_web();
currentUser = web.get_currentUser();
currentUser.retrieve();
context.load(web);
context.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
The executeQueryAsync method, after it retrieves the current user information, calls the onQuerySuceeded function that then completes the processing of that request. For example, something like this would be a simple example of that callback
function onSuccessMethod(sender, args) {
var userObject = web.get_currentUser();
alert('User name:' + userObject.get_title());
}
In between the time that the executeQueryAsync is called and the callback to the onSuccessMethod function occurs any other code that was downstream executes. This makes for awkward logic and flow in client object model programs. This is especially true when building larger applications that may want to reuse, let’s say, a function called getUserInformation which returns the current user as an object. This is where a little jQuery magic can come in handy. jQuery supports using what it refers to as Deferreds. Deferreds are based on a CommonJS Promises/A design. At the bottom of this post I will provide a link to documentation on Deferreds and the CommonJS Promise/A design, but for now let’s look at an example of how we can use this.
Let’s say I wanted to build a function like I mentioned above. A function that retrieves the current user’s information and returns that as an object. Since this request is asynchronous, this could normally be very problematic, but with a Deferred object it can be done simply. First, the initial function:
function getUserInformation() {
var dfd = $.Deferred(function(){
context = new SP.ClientContext.get_current();
web = context.get_web();
currentUser = web.get_currentUser();
currentUser.retrieve();
context.load(web);
context.executeQueryAsync(
function(){
var userObject = web.get_currentUser();
dfd.resolve(userObject);
},
function(){
dfd.reject(args.get_message());
}
);
});
return dfd.promise();
}
This function creates a Deferred object, then it runs the same code as above to request the current user. The callback functions have been embedded into the executeQueryAsync method so that I can easily reference my existing Deferred object. Notice that the function itself does not return the user object. This is because when the function completes processing the user object has not yet returned. It will be return later asynchronously. Instead, the function returns a promise; a contract that there will be a return value in the future. When the callback does occur then the Deferred object is resolved and any code waiting for the object to return can execute. For illustration purposes here is a simple call to this function that creates a popup message box with the current user’s name (via the title property).
getUserInformation().done(function(user){
alert('User name:' + user.get_title());
});
The nice feature with this is that if later I want to return that same user’s email address I can just as easily do that reusing the same function:
getUserInformation().done(function(user){
alert('Email address:' + user.get_email());
});
To learn more about promises and Deferred objects visit these link