Why promises?
Synchronous operations guarantee some maintenance easiness to code. But in the world of asynchronous operations, callbacks are the disguised maintenance monsters waiting for their turn. It is quite easy to get lost in a series of async operations and its callbacks. Attaching callbacks to async operations and invoking other async operations in callbacks can be equated to the future chaos. The Deferred and the Promises help us face such scenarios in a semantically justifying wayThe trivial promise pun
We tend to give promises to fill the gap of possible insecurity over some matter. jQuery promises are nothing different in its purpose.
I went to a food court last evening and ordered a yummy dinner at the South Indian Counter. The guy who took my order gave an “alarm disc” (Don’t know the exact name for fancy disco light disc which alarms when the food is ready at the counter)
With the disc, I went to wash my hands, I texted my friend, checked out the latest feed updates in Facebook and engaged in blabber with the friends who accompanied me, all quite peacefully - Just because I had a promise for the dinner with me - the alarm disc!
There are two point of contacts now, that can let me know about the ordered dinner; One the promise given from counter and the other the counter itself.
Hence, after waiting for a while I walked into the counter to know the baking status of my dinner.It was still being baked. A few minutes passed. Suddenly, in an unknown moment the alarm rang and I grabbed my dinner from the counter. This is quite normal.
After all, Deferred can actually change the status of async operation to the resolved state after successful completion of the process or to the failed state on failure, specifically only once. In other words, deferred has the privilege to decide that the operation is a success or failure, depending on the situation.
The promise object allows listening to an async operation – just like I stayed tune to the table alarm disc. While promise allows state inspection, it is always immutable.
Deferred potentially can be the state changing private area of the application that performs an asynchronous operation, while promise is the public handle or component of the Deferred that can be passed among the application modules that are interested in the state changes. In effect, this decouples the actual operation from its consumers.
Following are the state changing methods of the Deferred.
I went to a food court last evening and ordered a yummy dinner at the South Indian Counter. The guy who took my order gave an “alarm disc” (Don’t know the exact name for fancy disco light disc which alarms when the food is ready at the counter)
With the disc, I went to wash my hands, I texted my friend, checked out the latest feed updates in Facebook and engaged in blabber with the friends who accompanied me, all quite peacefully - Just because I had a promise for the dinner with me - the alarm disc!
There are two point of contacts now, that can let me know about the ordered dinner; One the promise given from counter and the other the counter itself.
Hence, after waiting for a while I walked into the counter to know the baking status of my dinner.It was still being baked. A few minutes passed. Suddenly, in an unknown moment the alarm rang and I grabbed my dinner from the counter. This is quite normal.
Deferred can give a promise
Deferred is analogous to the counter which initiated the baking of my dinner, an asynchronous operation that takes some time. Thus Deferred represents an operation that will be completed in future. I can get a promise from the Deferred. The promise let me know exactly when the result of that asynchronous operation is ready. Analogous to the counter, the Deferred itself can also notify regarding same.After all, Deferred can actually change the status of async operation to the resolved state after successful completion of the process or to the failed state on failure, specifically only once. In other words, deferred has the privilege to decide that the operation is a success or failure, depending on the situation.
The promise object allows listening to an async operation – just like I stayed tune to the table alarm disc. While promise allows state inspection, it is always immutable.
Deferred potentially can be the state changing private area of the application that performs an asynchronous operation, while promise is the public handle or component of the Deferred that can be passed among the application modules that are interested in the state changes. In effect, this decouples the actual operation from its consumers.
Following are the state changing methods of the Deferred.
- resolve
- resolveWith
- reject
- rejectWith
- done
- fail
- then
Deferred - Official definition
A constructor function that returns a chainable utility object with methods to register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function.
The below example might explain the above definition better. Line 1 invokes the constructor function. Deferred begins with the pending state.
Jquery animation is yet another asynchronous operation which returns a promise. Before Jquery 1.8 to attach a callback after animation is completed
var deferred = $.Deferred(); deferred.always(function() { }).done(function() { }).fail(function() { }).then(function(){ });All the callbacks added above are queued for execution on state changes. deferred.resolve() or deferred.reject() triggers state changes and also the execution of associated callbacks. “then” callbacks are triggered for both resolved and rejected deferred promises.
Handling callbacks blissfully
Jquery ajax method provided means to attach the success and error handling callbacks to it. Since Jquery 1.5 asynchronous processes such as AJAX returns jqXhr object which implements promise interface or otherwise it “is a” promise. As of Jquery 1.8, using success, error and complete handlers in AJAX is deprecated. It is recommended to use$.ajax().done(function() { }).fail(function() { });
Jquery animation is yet another asynchronous operation which returns a promise. Before Jquery 1.8 to attach a callback after animation is completed
$(“#container”).animate({ height: 100px; }, 5000, function() { //callback to be executed after animation });Since 1.8 as the animate returns a promise
$(“#container”).animate({ height: 100px; }, 5000). done(function() { //callback to be executed after animation });
It is good to know that when an element or a collection of elements undergo animation, a Deferred object would be assigned to the data attribute. Here the promise can be returned from the DOM element/collection which will be listened for completion of all animation on the corresponding element/collection.
$( "div" ).each(function( i ) { $( this ).fadeIn().fadeOut( 1000 * ( i + 1 ) ); }); $( "div" ).promise().done(function() { console.log( "Finished all animations on div collection!" ); });
The nifty when
$.when can accept a set of Deferred objects. The when method returns a promise from a new master deferred object which keeps track of each individual deferred object passed. Master deferred object will be resolved if all the individual deferred objects are resolved and rejected when atleast one of the deferred objects is rejected. Following example from Jquery website throws light into the usage.
The fail callback associated with when can serve as an area to perform some cleaning up for the requests already in progress that became invalid due to the fact that some other operation in the queue has failed.
var d1 = new $.Deferred(); var d2 = new $.Deferred(); var d3 = new $.Deferred(); $.when( d1, d2, d3 ).done(function ( v1, v2, v3 ) { console.log( v1 ); // v1 is undefined console.log( v2 ); // v2 is "abc" console.log( v3 ); // v3 is an array [ 1, 2, 3, 4, 5 ] }); d1.resolve(); d2.resolve( "abc" ); d3.resolve( 1, 2, 3, 4, 5 );
The fail callback associated with when can serve as an area to perform some cleaning up for the requests already in progress that became invalid due to the fact that some other operation in the queue has failed.