Read more

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

Henning Koch
April 15, 2016Software engineer at makandra GmbH

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

Illustration book lover

Growing Rails Applications in Practice

Check out our e-book. Learn to structure large Ruby on Rails codebases with the tools you already know and love.

  • Introduce design conventions for controllers and user-facing models
  • Create a system for growth
  • Build applications to last
Read more Show archive.org snapshot

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.

Posted by Henning Koch to makandra dev (2016-04-15 14:38)