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 online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
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)