SHARE
Facebook X Pinterest WhatsApp

jQuery Promises & Deferred: How to Use Them

Written By
thumbnail
Rob Gravelle
Rob Gravelle
May 29, 2013

5/28/13

Promises are like babies: easy to make, hard to deliver. ~Author Unknown

Remember when you wanted to associate an event handler to a mouseclick, you would assign it to the element’s onclick event, as in mywidget.onclick = myhandler;. This became problematic when another method also wanted to get in on the click action since you could only assign one function at a time. Eventually, the issue was solved by the addEventListener() DOM function, which allowed you to add as many listeners as you wanted. Fast forward to the present, and a similar problem has emerged with Ajax calls. This time it’s Ajax’s limitation of only supporting one callback function. jQuery introduced the Deferred object in version 1.5 to solve this problem. It can register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function. In today’s article, we’ll learn how to use the Deferred object with Promises.

What’s In a Promise?

Prior to jQuery 1.5, a typical Ajax call looked like this:

$.ajax({
  url: "/ServerResource.txt",
  success: successFunction,
  error: errorFunction
});

Since then, Ajax calls’ return object (jQuery XMLHttpRequest (jqXHR)) implements the CommonJS Promises/A interface, which offers greater flexibility and, hopefully, consistency across libraries.

var promise = $.ajax({
  url: "/ServerResource.txt"
});
 
promise.done(successFunction);
promise.fail(errorFunction);
promise.always(alwaysFunction);

The always() handler, referred to as complete() before jQuery 1.6, executes after the done() or fail() events, regardless of the Ajax call result.

All three done(), fail(), and always() handlers return the same jQuery XMLHttpRequest (jqXHR) object, so it is perfectly acceptable to chain them together:

$.ajax( "example.php" )    
    .done(function() { alert("success"); })    
    .fail(function() { alert("error"); })    
    .always(function() { alert("complete"); }); 

However, you will have to store the jqXHR object to a variable if you need to refer to it further down the line:

var jqxhr = $.ajax( "example.php" )    
    .done(function() { alert("success"); })    
    .fail(function() { alert("error"); })    
    .always(function() { alert("complete"); }); 
    
    // perform some work here ... 
    
    // Set another completion function for the request above
    jqxhr.always(function() { alert("another complete"); });

Another way to combine the handlers is to use the then() method of the Promise interface. It accepts all three handlers as arguments. With regards to jQuery, prior to version 1.8, you could pass an array of functions to the then() method:

$.ajax({url: "/ServerResource.txt"}).then([successFunction1, successFunction2, successFunction3], 
                                          [errorFunction1, errorFunction2]);

//same as

var jqxhr = $.ajax({
  url: "/ServerResource.txt"
});
 
jqxhr.done(successFunction1);
jqxhr.done(successFunction2);
jqxhr.done(successFunction3);
jqxhr.fail(errorFunction1);
jqxhr.fail(errorFunction2);

Since 1.8, the then() method returns a new promise that can filter the status and values of a deferred through a function, replacing the now-deprecated deferred.pipe() method. For all signatures, the arguments can be set to null if you don’t want to assign a handler for that event type. Best of all, you can rest assured that callbacks are guaranteed to run in the order they were passed in.

var promise = $.ajax({
  url: "/ServerResource.txt"
});
 
promise.then(successFunction, errorFunction);

 

var promise = $.ajax({
  url: "/ServerResource.txt"
});

promise.then(successFunction); //no handler for the fail() event

Chaining then() Functions

Then functions can be chained together to call multiple functions in succession:

var promise = $.ajax("/myServerScript1");
 
function getStuff() {
    return $.ajax("/myServerScript2");
}
 
promise.then(getStuff).then(function(myServerScript2Data){
  // Do something with myServerScript2Data
});

Combining Promises

The Promise $.when() method is the equivalent of the logical AND operator. Given a list of Promises, when() returns a new Promise whereby:

  • When all of the given Promises are resolved, the new Promise is resolved.
  • When any of the given Promises is rejected, the new Promise is rejected.

The following code uses the when() method to make two simultaneous Ajax calls and execute a function when both have successfully finished:

var jqxhr1 = $.ajax("/ServerResource1.txt");
var jqxhr2 = $.ajax("/ServerResource2.txt");
 
$.when(jqxhr1, jqxhr2).done(function(jqxhr1, jqxhr2) {
  // Handle both XHR objects
  alert("all complete");
});

Promise States

At any moment in time, promises can be in one of three states: unfulfilled, resolved or rejected. The default state of a promise is unresolved. Any handlers set are queued to be executed later. For instance, if an Ajax call is successful then $.resolved is called, its state is set to resolved and any “done” handlers set are executed. Should the call fail, $.rejected is called, its state is set to rejected and any “fail” handlers set are executed.

Making Your Own Deferred Process

By creating a new Deferred object via the jQuery.Deferred() method, we can setup our own deferred processes. In the following example, a <DIV> or <SPAN> element is updated based on the state of our process. The setInterval() method starts the process in motion, while setTimeout() determines when the process should end. Inside the process() method, a Deferred object is assigned to a local variable so that we can call its resolve(), promise(), and notify() events:

var timer;
$('#result').html('waiting…');
 
var promise = process();
promise.done(function() {
  $('#result').html('done.');
});
promise.progress(function() {
  $('#result').html($('#result').html() + '.');
});

function process() {
  var deferred = $.Deferred();

  timer = setInterval(function() {
    deferred.notify();
  }, 1000);
  
  setTimeout(function() {
     clearInterval(timer);
     deferred.resolve();
  }, 10000);
  
  return deferred.promise();
}

It can also be written using the then() method:

var timer;

(function process() {
  $('#result').html('waiting…');
  var deferred = $.Deferred();
    
  timer = setInterval(function() {
    deferred.notify();
  }, 1000);
  
  setTimeout(function() {
     clearInterval(timer);
     deferred.resolve();
  }, 10000);
  
  return deferred.promise();
})().then(function() { $('#result').html('done.'); },
          null,
          function() { $('#result').html($('#result').html() + '.'); });

Conclusion

Promises are definitely the new way to go when handling asynchronous processes. Forget about traditional callbacks and give the Promises/A API a try. It’s a big step in the right direction.

Recommended for you...

The Revolutionary ES6 Rest and Spread Operators
Rob Gravelle
Aug 23, 2022
Ahead of Time (AOT) Compilation in Angular
Tariq Siddiqui
Aug 16, 2022
Converting a JavaScript Object to a String
Rob Gravelle
Aug 14, 2022
Understanding Primitive Type Coercion in JavaScript
Rob Gravelle
Jul 28, 2022
HTML Goodies Logo

The original home of HTML tutorials. HTMLGoodies is a website dedicated to publishing tutorials that cover every aspect of being a web developer. We cover programming and web development tutorials on languages and technologies such as HTML, JavaScript, and CSS. In addition, our articles cover web frameworks like Angular and React.JS, as well as popular Content Management Systems (CMS) that include WordPress, Drupal, and Joomla. Website development platforms like Shopify, Squarespace, and Wix are also featured. Topics related to solid web design and Internet Marketing also find a home on HTMLGoodies, as we discuss UX/UI Design, Search Engine Optimization (SEO), and web dev best practices.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.