Lots of times I find myself making a bunch of async things like ajax requests, one after the other. Where the result of the first one is required in the second one. For e.g.

It usually looks like this:

This right moving code can very quickly become:

  • annoying
  • not pleasent to write
  • hard to maintain
  • and hard to debug in
  • plus it’s killing my 80 char word wrap column
  • more stacks than one may like

A better solution: jQuery’s Deferred Concept

Let’s start by using the deferred object to re-write the code we had above which had functions wrapped inside the success callbacks.

Ajax methods by default in jQuery are returning a promise of a deferred object which is created withe every ajax request. jQuery is also internally calling resolve on the deferred object when the ajax is successfully and calling reject when the ajax method fails. This updates the state on the promise and fires our callbacks attached to it via the then method.

The thing to note here is that then calls the next function only after the first functions promise has been resolved.

So jQuery did a lot of thing’s here for us when we used the ajax method. But promises in jquery are not limited to ajax and can be used anywhere you want. Below you will see how.

Exploring jQuery’s Deferred Object

jQuery provides a deferred object which can be created by using its factory method $.Deferred([beforeStart]). The deferred object has promise which can be returned when you the value is unknown and you want to return something so the receiver can proceed and call the next based upon its value. This is done by using the then method available on the promise. The first method which returned the deferred object can call resolve on the deferred object when the value is known and at that time the methods waiting on its promise will execute. Lets see an example.

We want to increase the height of a div from 100 to 500 and then let the next function know to put content in the div. The content should only be placed after the the width has increased.

Lets go over the API’s available in the jQuery Deferred Object.

  • $.Deferred([beginMethod]): Factory method to create the deferred object in its initial state of pending

  • deferredObj.resolve(args): This moves the state of the promise to resolved and thus causes the done listeners on the promise to fire. It passes args to the ha__ndler. The args could represent the value which was pending and is now available.

  • deferredObj.reject(args): This moves the state of the promise to rejected and thus causes the fail listeners on the promise to fire. It passes args to the handler.

  • deferredObj.notify(args): This does not change the state but causes the progress listeners on the promise to fire. It passes args to the handler.

  • deferredObj.state(): This returns the state of the promise/deferred object. It could be pending, resolved or rejected

  • deferredObj.promise(): gives an object which can be returned and observed for when the value is available

  • promiseObject.then(df,[ff],[pf]): takes methods to be called when the promise is resolved, rejected or has progress

  • promiseObject.done(df): takes method to be called when the promise is resolved

  • promiseObject.always(af): takes method to be called when the promise is either resolved, rejected or has progress

  • promiseObject.fail(ff): takes method to be called when the promise has failed

  • promiseObject.progress(pf): takes method to be called when the promise has progress

  • $.when(promise, [promise+]): returns a promise which changes state only when all the promises passed in resolve.

The deferredObj and promiseObject object are the same thing besides the subtle difference that on the promise object one can not call resolve, reject, notify etc. Therefore the promise object is only good for listening and thus an excellent candidate to be returned by the original method. Now all methods can be called on the deferred object but you should return the promise object and add callbacks on it. So in short: Change state of deferred and listen for state change on promise.

The when factory method is excellent choice when you want to create a new promise which is a combination of other promises. For e.g.

Now sometimes, things might finish up and faster than you expect. Meaning the state on a deferred will move from pending to resolved even before you get an opportunity to add an event handler on the promise of that deferred object. This is non-issue here because any handler added after the state has changed would fire immediately if its state had already been reached. For e.g.

References: