jQuery promises: done() and then() are not the same

jQuery's deferred Show archive.org snapshot objects behave somewhat like standard promises Show archive.org snapshot , but not really.

One of many subtle differences is that there are two ways to chain callbacks to an async functions.

The first one is done, which only exists in jQuery:

$.ajax('/foo').done(function(html) {
  console.debug("The server responded with %s", html);
});

There is also then, which all promise libraries have:

$.ajax('/foo').then(function(html) {
  console.debug("The server responded with %s", html);
});

However, .done() and .then() do not behave the same. In particular, if a standard promise callback returns another promise, this will delay the resolution of all later promises. jQuery's then behaves like this, but done does not. It is not possible for a done callback to delay the resolution of later callbacks.

Always prefer .then() so your code is compatible with the open promise standard ( Promises/A+ Show archive.org snapshot ).

Example

We want to request /foo and, as soon as we have the response, make a second request to /bar:

var promise = $.ajax('/foo').done(function() {
  return $.ajax('/bar');
});

Quiz: When does promise resolve?

Well, if you use done, it will resolve as soon as we have the response to /foo:

var promise = $.ajax('/foo').done(function() {
  return $.ajax('/bar'); // Returning does not actually do anything here.
});

promise.then(function() {
  console.debug("We have the response to /foo, but /bar is still loading");
});

If we use then instead, it will only resolve once we have responses to both /foo and /bar:

var promise = $.ajax('/foo').then(function() {
  return $.ajax('/bar');
});

promise.then(function() {
  console.debug("We have the responses to both /foo and /bar");
});

Enjoy.

Henning Koch About 8 years ago