In order to master Deferreds and Promises you have to understand when to use one and when the other. To help you understand this topic, let’s say that you want to implement a promise-based timeout function. You are the producer of the function. In this case, the consumer of your function doesn’t need to care about resolving or rejecting it. The consumer only needs to be able to add handlers to execute operations upon the fulfillment, the failure, or the progress of the Deferred. Even more, you want to ensure that the consumer isn’t able to resolve or reject the Deferred at their discretion.
To achieve this goal, you need to return the Promise object of the Deferred you’ve created in your timeout function, not the Deferred itself. To be able to do that, we need to introduce you to another method called deferred.promise().
Method syntax: deferred.promise | |
---|---|
deferred.promise([target]) | |
Return the Deferred’s Promise object. | |
Parameters | |
target | (Object) An object to which the promise methods will be attached. If this parameter is provided, the method attaches the Promise behavior to it and returns this object, instead of creating a new one. |
Returns | |
The Promise object. |
Now that you know about the existence of this method, let’s write some code to use it. The code is shown in the next listing, available as a JS Bin and in the file lesson-13/promise.timer.html.
Listing 13.5. A promise-based timer

In this listing you define a function called timeout() that wraps the JavaScript set-Timeout() function. Inside timeout() you create a new Deferred object (you’re the producer) and arrange that setTimeout() resolves this Deferred after a given number of milliseconds
. Once finished, you return the Deferred’s Promise object
. Doing so, you ensure that the caller of your function (the consumer)
can’t resolve or reject the Deferred object but can only add callbacks to execute using methods like deferred.done() and deferred.fail().
The previous example is pretty simple and may not have entirely clarified when to use a Deferred and when to use a Promise object. For those of you who still have doubts, let’s discuss another example. We’ll revisit our progress bar demo so that the animate() function will focus on animating the progress bar only, freeing it from the responsibility of updating the text showing the percentage of completion. Hence, it’s the caller of the function that has to update the text percentage and, optionally, perform other tasks when the Deferred is resolved or rejected.
The new version of this code is shown in the following listing and is also available as a JS Bin and in the file lesson-13/deferred.progress.2.html. Note that in this listing we’ve omitted the style of the page so that you can focus on the code. In addition, we’ve bolded the parts that are changed in comparison with the previous version.
Listing 13.6. Using deferred.progress(), version 2


As you can see, in this version of the animate() function you only create the Deferred . Once the code that runs the animation has been set, you return its Promise so that the caller of this method can add callbacks
. Once again, you’re returning the Promise because you want to enable the caller to add callbacks but not to be able to change the state of the Deferred. In this case, it’s the responsibility of the function that created the Deferred to either resolve or reject it.
Finally, inside the handler that’s attached to the click event of the button you define a callback to run during the progress of the animation using deferred .progress() , and then a callback to execute when the Deferred is resolved, using deferred.done() (this was absent in the previous version)
.
With this example we’ve hopefully reinforced the concepts and the methods described so far. The most observant of you may have noted that we haven’t yet covered the only method mentioned by both the Promises/A and the Promises/A+ specifications, the then() method. Let’s fix that.
Take it short with then()
In section 13.1 we summarized the definitions of promise taken by the Promises/A and the Promises/A+ proposals. Both of these definitions mention a then() method, but whereas the Promises/A proposal specifies that the method must possess a third argument that will be used as a handler for a progress event, the Promises/A+ proposal doesn’t have such an argument. The jQuery implementation of this method prior to version 3 (branches 1.x and 2.x) differs from both these proposals because it defines the first argument, the success callback, as mandatory and the other two, the failure and progress callbacks, as optional. In contrast, the Promises/A and Promises/A+ proposals specify that all their arguments are optional.
The deferred.then() method can be used as a shortcut for calling deferred.done(), deferred.fail(), and deferred.progress() when you only need to execute one handler for each or some of these methods. In case you need more handlers of the same type, you can chain calls to then(), done(), fail(), and progress(). Moreover, if you don’t need a handler of a given type, you can simply pass null. For example, you can write a code statement like the following:
$.Deferred()
.then(success1)
.then(success2, null, progress1)
.done(success3);
Now that you know what this method can do for you, it’s time to learn its syntax.
Method syntax: deferred.then | |
---|---|
deferred.then(resolvedCallback[, rejectedCallback [, progressCallback]]) | |
Defines handlers executed when the Deferred object is resolved, rejected, or in progress. In case one of these parameters isn’t needed, you can pass null. | |
Parameters | |
resolvedCallback | (Function) A function executed when the Deferred is resolved. |
rejectedCallback | (Function) A function executed when the Deferred is rejected. |
progressCallback | (Function) A function executed when the Deferred is in progress. |
Returns | |
A Promise object. |
The deferred.then() method returns a Promise object instead of a Deferred. After you invoke it, you won’t be able to resolve or reject the Deferred you used unless you keep a reference to it. Recalling the handler of the click event of the button defined in listing 13.6, using the deferred.then() method you could rewrite it as follows, obtaining the same result:
animate(1000).then(
function() {
alert('The process is completed');
},
null,
function (value) {
$('.progress').text(Math.floor(value) + '%');
}
);
What makes this method even more interesting is that it has the power to forward the value received as a parameter to other deferred.then(), deferred.done(), deferred .fail(), or deferred.progress() calls defined after it.
Before you start to cry in despair, let’s look at a simple example:
var deferred = $.Deferred();
deferred
.then(function(value) { return value + 1; })
.then(function(value) { return value + 2; })
.done(function(value) { alert(value); });
deferred.resolve(0);
This code creates a new Deferred and then adds three functions to execute when it’s resolved, two using the deferred.then() method and one using deferred.done(). The last line resolves the Deferred with a value of 0 (zero), causing the execution of the three functions defined (in the order in which they were added).
Inside the functions added using deferred.then() you return a new value, created starting from the one received. The first function receives the value 0 because this is the value passed to deferred.resolve(), sums it to 1, and returns the result. The result of the sum is passed to the next function added using deferred .then(). The second function receives 1 instead of 0 as an argument. This value (1) is summed to 2 and the result returned (3) is used by the next handler. This time, the handler is added using deferred.done(), which doesn’t have this power, so you alert the final value, 3.
If you add yet another function using deferred.done() to the chain in the previous example and return a modified value from the third in the chain (the one added using deferred.done()), the new handler will receive the same value as the third. The following code will alert the value 3 twice:
var deferred = $.Deferred();
deferred
.then(function(value) { return value + 1; })
.then(function(value) { return value + 2; })
.done(function(value) { alert(value); return value + 5; })
.done(function(value) { alert(value); });
deferred.resolve(0);
In Promises/A and Promises/A+ compliant libraries (for example, jQuery 3.x), a thrown exception is translated into a rejection and the failure callback is called with the exception. In jQuery 1.x and 2.x an uncaught exception will halt the program’s execution. Consider the following code:
var deferred = $.Deferred()
deferred
.then(function(value) {
throw new Error('An error message');
})
.fail(function(value) {
alert('Error');
});
deferred.resolve();
In jQuery 3.x, you’ll see an alert with the message “Error.” In contrast, jQuery 1.x and 2.x will allow the thrown exception to bubble up, usually reaching window.onerror. If a function for this isn’t defined, you’ll see on the console the message “Uncaught Error: An error message.”
You can investigate this issue further to better understand this different behavior. Take a look at the following code:
var deferred = $.Deferred();
deferred
.then(function() {
throw new Error('An error message');
})
.then(
function() {
console.log('First success function');
},
function() {
console.log('First failure function');
}
)
.then(
function() {
console.log('Second success function');
},
function() {
console.log('Second failure function');
}
);
deferred.resolve();
In jQuery 3.x, this code would write on the console the messages “First failure function” and “Second success function.” The reason is that, as we mentioned, the specification states that a thrown exception should be translated into a rejection and the failure callback has to be called with the exception. In addition, once the exception has been managed (in our example by the failure callback passed to the second then()), the following success functions should be executed (in this case the success callback passed to the third then()).
In jQuery 1.x and 2.x, none but the first function (the one throwing the error) is executed. You’ll only see on the console the message “Uncaught Error: An error message.”
jQuery 3: Method added
jQuery 3 adds a new method to the Deferred and the Promise objects called catch(). It’s a method to define a handler executed when the Deferred object is rejected or its Promise object is in a rejected state. Its signature is as follows:
deferred.catch(rejectedCallback)
This method is nothing but a shortcut for then(null, rejectedCallback) and it has been added to align jQuery 3 even more to the ECMAScript 2015 specifications that include a namesake method.
Despite these differences of the jQuery library from the specifications, Deferred remains an incredibly powerful tool to have under your belt. As a professional developer and with the increasing difficulty of your projects, you’ll find yourself using it a lot.
Sometimes, regardless of the state of a Deferred, you’ll want to perform one or more actions. jQuery has a method for such circumstances, too.
Always execute a handler
There may be times when you want to execute one or more handlers regardless of the state of the Deferred. To do that you can use the deferred.always() method.
Method syntax: deferred.always | |
---|---|
deferred.always(callbacks[, callbacks, …, callbacks]) | |
Add handlers that are called when the Deferred object is either resolved or rejected. This method accepts an arbitrary number of callbacks with a minimum of one. | |
Parameters | |
callbacks | (Function|Array) A function or array of functions that is called when the Deferred is either resolved or rejected. |
Returns | |
The Deferred object. |
Consider the following code:
var deferred = $.Deferred();
deferred
.then(
function(value) {
console.log('success: ' + value);
},
function(value) {
console.log('fail: ' + value);
}
)
.always(function() {
console.log('I am always logged');
});
deferred.reject('An error');
When executing this code, you’ll see two messages on the console. The first is “fail: An error” because the Deferred has been rejected. The second is “I am always logged” because the callbacks added using deferred.always() are executed regardless of the resolution or rejection of the Deferred.
There’s one last method to discuss.
Determine the state of a Deferred
When writing code that uses a Deferred, you may need to verify its current state. To do that, you can employ the deferred.state() method. It does exactly what you’d expect: it returns a string that specifies the current state of the Deferred. Its syntax is the following.
This method is particularly useful when you want to unit-test your code. For example, you could write a statement like this:
assert.equal(deferred.state(), 'resolved');
The method used in the previous statement comes from the QUnit unit-testing framework that we’ll discuss in the next lesson. It simply verifies that the first parameter is equal to the second, in which case the test passes.
Leave a Reply