Using jQuery Promises & Deferreds with SharePoint 2013 JSOM

When you dive into client side SharePoint 2013 Development, one of the first challenges you’ll encounter is that the object model only supports ExecuteQueryAsync and not its synchronous version ExecuteQuery.

What does this mean?

When you call ExecuteQuery in CSOM on the server side, it executes the object model code you declared and doesn’t return until its done. It runs the code, waits, and then returns. This is a synchronous call.

When you call ExecuteQueryAsync in JSOM on the client side, it executes the object model code you declared and carries on immediately! Then at some point in the future it returns. This is an asynchronous call.

This is challenging because rarely do we need to do a single thing with the object model and quite often we need to act on the result of that execution. So we need to wait and then do something.

How do we handle this?

The answer is promises. Promises is simply a programming paradigm that deals with the challenges of asynchronous calls. It does this by deferring the execution of some work until something else has finished.

Like it promised. Get it?

Here’s a simple example:

var p = doWork();
p.done(function(result) {
    doSomeOtherWork();
});

In this example, doWork returns a promise. I’ve named the variable ‘p’ as its become somewhat of a convention, the way ‘i’ is often used in a for loop for the index. A promise is simply an object with callback functions that will be executed when the promise is complete.

In this example I am only using the done callback. There is also a fail callback for when the promise isn’t completed, or in promise terminology: it isn’t fulfilled.

So how do you return a promise from your own functions?

In order to return a promise, you need to create an object called a Deferred. Its very simple, and it gives you access to a promise:

function doWork() {
    var d = $.Deferred();
 
    // some asynchronous task like executeQueryAsync...
 
    return d.promise();
}

In this example I am creating a jQuery Deferred and then calling its promise() method to return a promise object. Remember, a promise is simply an object with some callbacks: done and fail. So how do we tell the outside world that our promise has been fulfilled?

We call another function on our Deferred. Resolve.

function successCallback(d) {
    d.resolve();
}

In this example, I have some callback that will be executed by my executeQueryAsync when it successfully completes. I need to make sure that function gets passed my deferred object that I created and then simply call the resolve() method on it.

So what happens if I fail?

function failCallback(d) {
    d.reject();
}

This example is very much like the previous one, but I’m simply calling reject instead of resolve(). This means the consumer of my promise will need to also handle the fail() callback as well as the done().

So how does this all work with executeQueryAsync?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function successCallback() {
    this.d.resolve(this.list);
}
 
function failCallback() {
    this.d.reject("something bad happened");
}
 
function getList(name) {
    var d = $.Deferred();
 
    var clientContext = SP.ClientContext.get_current();
    var list = clientContext.get_web().get_lists().getByTitle(name);
 
    var o = {d: d, list:list};
    clientContext.executeQueryAsync(Function.createDelegate(o, successCallback), Function.createDelegate(o, failCallback));
 
    return d.promise();
}
 
var p = getList("Documents");
p.done(function(result) {
    // result is an SP.List because that is what we passed to resolve()!
    var list = result;
    // do something with the list
});
p.fail(function(result) {
    // result is a string because that is what we passed to reject()!
    var error = result;
    console.log(error);
});

So this is a complete example and has a couple items we haven’t seen before.

The getList() function makes a call to the object model using executeQueryAsync and returns a promise because the object model code is not going to return right away. The promise isn’t resolved or rejected until executeQueryAsync returns.

You might be wondering why we are using the Function.createDelegate call.

We could have just passed the successCallback and failCallbacks on their own, but we would have lost the ability to control the context of those callbacks. What this means is the ‘this’ keyword.

Notice on line 15 we create a simple object containing our Deferred and our SP.List object. We pass that into our Function.createDelegate calls in order to invoke the callbacks in a way that sets their context (this) to that object! This is the way to pass parameters into callbacks using executeQueryAsync.

So you can now see how using jQuery Deferred’s and Promises can help manage working with JSOM and SharePoint. You can create other functions that wouldn’t be invoked until getList() was resolved by calling them inside the done() callback. Those could also return their own promises in order to manage the asynchronous nature of JSOM development.

Now go make some promises!

,

8 Responses to “Using jQuery Promises & Deferreds with SharePoint 2013 JSOM”

  1. John Guilbert November 8, 2013 at 9:59 am #

    Doesn’t Work! Where is your clientContext coming from. You don’t use context loading. Is this a pseudo code example?

  2. Shereen Qumsieh November 26, 2013 at 5:48 am #

    Hi John,

    Small typo, I’ve updated the code sample, but yes it does work.

  3. Rob Luton December 18, 2013 at 3:04 am #

    Hi Shereen,
    I have a fairly complex app that depends on the JSOM. I’ve been trying to get the deferred to work correctly for some time. I have followed your example, but my deferred always triggers the fail method. I am fairly sure this is because when I go to grab the current context, the SP object is undefined or null. That would makes sense if I was using the ExecuteOrDelayUntilScriptLoaded method, but I am using it. I suspect that, in your example, to make sure sp.js is loaded already, you need to add ExecuteOrDelayUntilScriptLoaded(getList, “sp.js”) Would that be correct? Can you modify your example to include this concept? I am doing something similar, but for whatever reason, it is not working. My deferred fails every time. I am very close to going back to the pyramid of doom and executing my entire application inside the success callback :(

  4. John June 12, 2014 at 2:27 pm #

    Very useful example….thanks!

    But the list doesn’t populate with information unless you have a line 14:

    clientContext.load(list);

  5. Jo June 18, 2014 at 8:53 am #

    Thanks for this post! Yours is the only example I’ve managed to follow and get to work to retrieve a list item. I just had to remember to put context.load(myListItem); in before my call to executeQueryAsync.

    I have a question! When doing “normal” async calls to executeQueryAsync, I write:
    ctx.executeQueryAsync(Function.createDelegate(this, this.myQuerySuccess), Function.createDelegate(this, this.myQueryFailed));

    My failed function then looks like:

    function myQueryFailed(sender, args) { alert(args.get_message() + ‘\n’ + args.get_stackTrace); }

    How would I access the ‘args’ using your deferred method? I tried amending the failed method in your example to function failCallback(sender, args) { this.d.reject(args.get_message()); }, but this doesn’t work.

    Thanks for any assistance!

  6. Ankit July 4, 2014 at 5:38 am #

    Hello Shereen,
    Of all the Deferred Promise scattered over the Internet I find this much informative,simple and easy to use.

    Thanks Shereen for an wonderful post.

  7. Shereen Qumsieh July 15, 2014 at 5:20 pm #

    Thanks Ankit!

  8. Mattias October 23, 2014 at 11:27 am #

    Great example, how do you force to load jQuery when building a SharePoint 2013 SP-hosted app?

Leave a Reply