tag tips, javascript, ajax, jquery, deferred

Fun With jQuery Deferred

If you've upgraded to the recently released jQuery 1.5 you may have heard about the fancy new AJAX facilities that allow you to define things like this:

var jax = $.ajax({
  url: '/some/url'
})

jax.success(function() {
  alert("It worked!");")
});

Well, that new power is known as Deferreds and it can be useful in more places than straight-up AJAX callbacks. If you want an in-depth look at the Deferred API you can look at the jQuery Documentation or read this very in-depth look at the API. But we're here today to take a look at a few practical examples that will let you really get the most out of the new functionality.

A More Expressive setTimeout

I've always hated the Javascript API for setTimeout. In my opinion it just doesn't make sense to have the duration come after the function. Using Deferreds, we can write a very English-friendly syntax for timeouts.

$.wait = function(time) {
  return $.Deferred(function(dfd) {
    setTimeout(dfd.resolve, time);
  });
}

Now, thanks to the Deferreds, I can write timeouts in my app like this:

$.wait(5000).then(function() {
  alert("Hello from the future!");
});

This is just a small example, but it shows you how easy it is to write deferred functionality into your applications. For our next trick, let's get a little more complex.

Pretty Little Wrapper

A common thing I find myself doing in jQuery is writing a small wrapper for an API. I always hate how messy the callback code gets, let's see if we can clean it up a bit using Deferreds.

Twitter = {
  search:function(query) {
    var dfr = $.Deferred();
    $.ajax({
     url:"http://search.twitter.com/search.json",
     data:{q:query},
     dataType:'jsonp',
     success:dfr.resolve
    });
    return dfr.promise();
  }
}

Now I can easily perform Twitter searches in my app like so:

Twitter.search('intridea').then(function(data) {
  alert(data.results[0].text);
});

The Advantages of Deferreds

Why would I want to use deferreds instead of standard callbacks? Well, for one, you can attach multiple callbacks to a deferred, giving you lots of flexibility in designing your application. Another way they're superior is by giving you built-in error handling. If you had a deferment that failed, you would be able to handle that as well:

function doSomething(arg) {
  var dfr = $.Deferred();
  setTimeout(function() {
    dfr.reject("Sorry, something went wrong.");
  });
  return dfr;
}

doSomething("uh oh").done(function() {
  alert("Won't happen, we're erroring here!");
}).fail(function(message) {
  alert(message)
});

Deferreds are just a simple and powerful tool for you to use to make your code cleaner, more readable, and more functional. This is really just scratching the surface, so if you have any other fun Deferred tricks, I'd love to see them in the comments!

Update: From the comments, I see that it is appropriate to return dfd.promise() instead of the deferred object itself. The code has been updated to reflect as much.