Web App Development

Using deferred objects in your own components

My previous post explained how to use the promise objects returned by jQuery methods. You can also use deferred objects in your own components or libraries and expose a promise object to the rest of the code.

Imagine you are animating several elements on you page. You can use deferred objects to add a completion handler to all of them in a clean way. (jQuery actually does this very well already - see below - but let's use this as an example.)

First let's load jQuery and add two div's to animate:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.js"></script>

<div id="div1" style="background:red; width: 40px; height: 40px;"></div>
<div id="div2" style="background:green; width: 40px; height: 40px;"></div>
Then add this Javascript code:
function myAnimate(element, css, duration) {
var deferred = $.Deferred();

$(element).animate(css, {
duration: duration,
complete: function () {
deferred.resolve();
}
});
return deferred.promise();
}

var animation1 = myAnimate("#div1", {
"width": "200px"
},
500);
var animation2 = myAnimate("#div2", {
"width": "200px"
},
1500);

$.when(animation1, animation2).then(function () {
$("#div1").html("Both done!");
});
The myAnimate function returns are jQuery promise object. You can then group the two promise objects using $.when.

Inside the myAnimate function we create a new deferred object using $.Deferred, do the actual animation and return a promise object (using .promise to generate the promise object).

In the animation complete handler we then resolve the deferred object. This triggers the any .done handlers attached to the promise object which are used by $.when to decide whether to call the $.then handler function.

Rejecting a deferred object

Calling .resolve indicates that the action has been completed successfully. If for some reason there is an error and the $.then handler code depends on it you can call .reject on the deferred object instead. This will trigger .fail on the promise  and the success trigger passed to $.then will not be executed. You can however pass a function as a second argument to $.then that will be run on rejection.

jQuery already has functionality built in for waiting for several animations to finish

So don't use the example above, use this instead:
$("#div1").animate({
"width": "200px"
}, {
duration: 500
});
$("#div2").animate({
"width": "200px"
}, {
duration: 1500
});

$("#div1, #div2").promise().done(function () {
$("#div1").html("Both done!");
});
.animate does not return a promise object and returns a jQuery object to maintain chainability. You can obtain a promise object for the animations by calling .promise on the jQuery object.


Comments


Follow me on Twitter