Understanding JQuery.Deferred and Promise

Please read my new and more accurate blog post about promises first: here

Notice this blog post has lot of runnable examples in Javascript, but it might not work on a rss reader.

JQuery 1.5 introduced the concept of “Deferred”, you can read more about it here. I find this concept very powerful when working with Javascript and ajax, and I think is a game changer to the way we are used to write asynchronous code in js.

Usually, the way we are used to deal with asynchronous code in Javascript is passing callbacks as an argument to the function:

As you can see here we are passing two callbacks (success and error) to the $.ajax method using the object-literal syntax that the method support.

This work but it is not an standard interface, it requires some work inside the post method and we can't register multiple callbacks.

Introducing $.Deferred

The deferred object is pretty easy to understand yet powerful. It has two important methods:

  • resolve
  • reject

And it has three important “events” or ways to attach a callback:

  • done
  • fail
  • always

so a basically dumb example will be something like this (you can run this right here):


If you call the "reject" method the fail callback attached will be executed, the always callback is executed whether the deferred is resolved or rejected.

Another interesting point is that if you attach a callback to an already resolved deferred, it get executes immediately:

The Promise() method

The Deferred object has another important method named Promise(). This method returns an object with almost the same interface than the Deferred, but it only have the methods to attach callbacks and does not have the methods to resolve and reject.

This is useful when you want to give to the calling API something to subscribe to, but not the ability to resolve or reject the deferred. This code will fail because the promise doesn't have a method "resolve":


The $.ajax method in JQuery returns a Promise, so you can do:

This code does the same than the first snippet with the only difference that you can add as many callbacks as you want, the syntax is clear because we don’t need an extra parameter in the method. On the other hand you can use the promise as a return value of other function and one of the most interesting things for me is that you can do some operations with the promises.

The Pipe() method

The Pipe method is very powerful and useful, it allows you to “project” a promise.

Following the former example, we can do something like this:


Here we are doing a projection of the result which is a “person” object. So, instead of having a Deferred of person, we have now a deferred of “Saved {firstName}”.

Another very interesting feature of the pipe method is that you can return a deferred from inside the pipe callback. Imagine that we have two methods, one to get a Customer SSN by an internal id fiscal and another one to get a Person’s address by SSN:

As you can see here, I added a new method “getPersonAddressByID”. This method return a deferred which is a combination of the two methods. If one of the methods in the pipeline fails the “master” deferred will fail.

Pipelines has some other usages, for instance, you can reject the deferred inside the pipe callback.

Another interesting use case that I can think of for pipes, are recursive deferred. Imagine that you started an asynchronous operation in the backend, and you need to do “polling” to see if the task is done and when the task is done do something else;

Combining promises with $.when

Another very useful method is $.when. The method accepts an arbitrary number of promises, and it returns a master deferred that:

  • will be “resolved” when all the promises are resolved,
  • will be rejected if any of the promises is rejected,

The done callback has the results of all the promises.

This is an example:

As you can see at the end of this example, then $.when returns a new deferred and we are using the two results in the done callback.

Notice that I changed the getCustomer method; this is because the promise of an ajax call, has the content payload as first element in the result, but also has other stuff like the status code.

In this  you can mix $.when and pipes as follows:

 

Another interesting use case for the $.when operator, is when you need to load several things in the screen but you want only one big-loading message:

 

There are other useful methods and ways you can combine deferred I strongly encourage to read about those in the jquery documentation.

This is all for now! I hope you find this post useful.


blog comments powered by Disqus
  • Categories

  • Archives