A task can succeed or fail, which is refelected by the state of the deferred instance. Deferreds provide two methods to change their state
- reject – deferred object is rejected and calls any fail-callbacks
- resolve – deferred object is resolved and calls any done-callback
A deferred’s state can only be set once. Finally, to get notified that the task is finished you can bind callback function to specific states
- done – the task was successful
- fail – the taks failed
- always – fires in both cases
Calling these functions multiple times enables you to register as many callback functions as you please.
Now that we have tackled the basics, lets explore Promises, $.when and Deferred.pipe, the real power of Deferreds.
Something used in the example above, but not explained yet is the promise() method. This method returns a read-only version of the deferred instance. It is a best practice not to return the deferred itself, but something known as a Promise. The Promise object can only be used to bind callbacks to the underlying deferred object and to retrieve state information.
Ajax requests use Deferreds too and they return a promise
However, it is not very often used this way, but if you do, you can register multiple callback functions to a success or failure state.
With Deferreds we’ve managed to simplify the work needed to manage one asynchronous task. Taking this one step further, jQuery.when lets you bind callbacks to a group of Deferreds. If two or more Deferreds are passed to jQuery.when it creates a new master Deferred and returns its Promise. This master Deferred’s state only changes if
- all Deferreds are resolved – resolved
- at least one Deferred is rejected – rejected
The following example demonstrates this by merging the output of two ajax request
So, enough surface scratching, lets deal with Deferred.pipe. This method lets you filter the result of a deferred, but it can also chain multiple Deferreds. Like Deferred.when, this method too creates a master deferred and returns its promise. The following example demonstrates filtering and chaining. It simulates an automatic stock trading application. For a given stock, a minimum and a maximum value, this app will tell you when to buy or sell
First Deferred.pipe is used to filter the outcome of the ajax request. The function buyOrSellTrigger actually does both. When it returns ‘BUY’ or ‘SELL’ it does filtering, but when it returns the recursive call to itself it does chaining, known as promise pipelining. Chaining happens when the parameter given to Deferred.pipe is a Deferred/Promise. In this case it is a function which returns a promise.
Animations are also asynchronous and use Deferreds as well. But the animate function behaves differently, it does not return a Promise, but a jQuery object, a wrapper around the DOM element in question. This is quite common for jQuery’s DOM manipulation functions, which facilitate method chaining. Fortunately, these wrapper objects have a method called promise(), not to be confused with Deferred.promise, but their behavior is identical. So, if a wrapper object instead of a promise is passed to a Deferred method, it is smart enough to first retrieves the Promise before it continues.
With Deferreds you have a powerful tool to manage asynchronous tasks and keep your code simple and maintainable.
But of course there are many other interesting Deferred methods, for example, to monitor progress or to inspect the state of a deferred instance. But those discussed here are really fundamental and contribute to the understanding of what Deferreds are and how they are used.