Tegud.NET

Blog - 2011

Sunday, 11 September 2011

Tuesday, 23 August 2011

This is the first of a three part blog series where I'm going to cover a feature of jQuery: deferreds. In Part One (here) we're going to cover the very basics, what they are and a simple example. In Part Two we'll have a much more useful example, before finally we'll cover the more advanced concepts around deferreds.

What are they?

jQuery deferreds were added during the overhaul of the AJAX module. Present in many other frameworks they provide a way of managing executing code upon completion of several asynchronous operations. As suggested by their inclusion during the overhaul of AJAX in jQuery, deferreds most obvious applications relate to AJAX.  Many examples focus on how deferreds can fire callbacks when several AJAX commands return.  In this and my next blog post I’m going to try and focus on showing first how deferreds work, and then to show a real life application (which does in fact use an AJAX request, but we’ll get to that).

Deferreds are a very powerful addition to jQuery and can help you tweak the execution to improve perceieved page load time to users, manage complex asynchronous activities and much more.  Rather than dive too much into the details of the methods available with deferreds, I’m going to try and show how it works at basic level in this post, provide a more practical case study in the 2nd post and then finally move onto a more in-depth look at the methods and properties available with deferreds in jQuery (in the future I also plan to do a blog post on deferreds in other frameworks).

First, a pointless example

Not the best advert, but this simple example doesn’t have much real life application. In this example we’re going to create three deferred objects and then use setTimeout() to resolve them at different times.  When each timeout elapses one of the LI elements is turned “on”. When all three deferreds have been resolved, the final div is turned “on” and it’s text set to done.

First thing we need to do is set up the three deferred objects. This is done simply enough:

var deferredA = $.Deferred(),
    deferredB = $.Deferred(),
    deferredC = $.Deferred();

Once we have the deferred object we can then set up how resolving them is handled. First thing we do is call the when method on the jQuery object.  This returns a chainable object, but it isn’t the usual jQuery object.  Another post will cover some of the other methods available , but for now the one we really care about is .then(). Then() accepts a callback as it’s parameter, once all the arguments to when() are resolved, this callback is fired.  Basically the logic you want executed when all deferred objects are resolved goes in then().  Putting this all together our deferred setup looks like this:

 $.when(deferredA,deferredB,deferredC)
      .then(function() {
          result.addClass('On').text('Done');
      });

All three deferred are passed to the $.when() function. Our “then” callback applies the class we want and sets the text to “Done” indicating all deferreds have been resolved.

Currently because we’re generating the deferreds manually we have to resolve them manually as well.  When using the deferreds returned from jQuery’s AJAX methods, they are resolved or rejected for us. We’ll cover how to handle errors later, for now we’ll stick to the basics.  In this example we’re going to resolve the deferreds using setTimeouts of various times.

setTimeout(function() {
    deferredA.resolve();
    ul.children(':eq(0)').addClass('On'); }, 500); 
}

setTimeout(function() {
    deferredB.resolve();
    ul.children(':eq(1)').addClass('On'); }, 3000); 
}

setTimeout(function() {
    deferredC.resolve();
    ul.children(':eq(2)').addClass('On'); }, 1500);
}

As each timeout fires, it resolves it’s deferred object, as soon as all the deferreds provided to the $.when() method are resolved, it fires the callback provided to .when().

I’ve posted a working example of this to jsbin.com so feel free to see it in action/tinker.

Show me something useful already

In the next part I'm going to explore a practical use for defers, one I've used at work, and plan on introducing to my site here as well.