Promises (aka Deferred): more efficient handling of async in JavaScript

  • Post by Nicolas Ramz
  • Jan 21, 2010
Promises (aka Deferred): more efficient handling of async in JavaScript

JavaScript: a single-threaded language with many asynchronous calls

JavaScript is a single-threaded language: it means that at a given time, only one script is being executed but a lot of things are asynchronous: you call a function that has to do some work and that function returns immediately. The best example would be the ajax calls: you send the request, and the browser returns immediately, executing what’s next on the stack. Once the result is received, JavaScript usually calls back a function you supplied

$.ajax('/myContent.html', function(result) {
    $('#myDiv').append(result);
});

In this very simple jQuery example, we are making an ajax call to get the result of /myContent.html file. Once we get a response, we append the received html to the #myDiv DOM element. Quite simple hey ? Now what if we want to make two calls: call1 and call2 and display an error if any of the calls produce an error. We could write this kind of code:

$('#myDiv').append(result);
}, function(error) {
  // error
  $('myDiv').append('Error');
})

$('/myContent2', function(result) {
  $('myDiv').append(result);
}, function(error) {
  $('myDiv').append('Error');
})

This works but the problem is that the error would be displayed twice. We could of course check for the error by setting a boolean variable, but still, this wouldn’t be the best way to describe this behavior.

Promises to the rescue

A promise represents the value of an async operation. A promise can have the following three states:

  • resolved
  • rejected
  • pending

Using jQuery’s implementation of the promises - called Deferred -. jQuery already makes use of promises for Ajax calls, so a simple Ajax call could be handled this way:

$.ajax('/content').done(function(result) {
  $('#myDiv').append(result);
}).fail(function(error) {
  $('#myDiv').append('error');
})

At first glance, this doesn’t look so much better than the first piece of code, right ? Well, the good thing about the promises, is that we may store the promise for later use and even chain them. Now let’s have a look at the previous piece of code. Using the promises we could write it like this:

// make an ajax call to myContent1, if sucessful append the result to #myDiv
var promise1 = $.ajax('/myContent1').done(function() {
  $('#myDiv').append(result); }
);

// make an ajax call to myContent2, if sucessful append the result to #myDiv
var promise2 = $.ajax('/myContent2').done(function() {
  $('#myDiv').append(result); }
);

Now checking that both ajax calls were successfull would be a matter of checking that both promises have been fullfilled:

$.when(promise1, promise2).done(function() {
  // both ajax calls were successful
  $.ajax('/content3').done();
}).fail(function() {
  $('#myDiv').append('error');
});