Making Sense of $.Deferred as a Promise

After searching for better clarity, I came across one of the best explanations of how jQuery implements Promise using the jQuery's Deferred object. This is especially useful given PromiseJS's FUD explanation of why to avoid jQuery deferred.promise() object.

After finding the information on PromiseJS a little too biased:

This feels like a good time to warn you that what jQuery calls a promise is in fact totally different to what everyone else calls a promise. jQuery's promises have a poorly thought out API that will likely just confuse you. Fortunately, instead of using jQuery's strange version of a promise, you can just convert it to a really simple standardised promise...

https://www.promisejs.org/

Read, "don't drive a car with a V8 because a V8 works differently than an inline 4" – granted it's not their responsibility to explain what jQuery was trying to do with patching the older and more complex deferred object. Add to that jQuery's less than clear explanation of their promise implementation in the $.Deferred object:

In most cases where a jQuery API call returns a Deferred or Promise-compatible object, such as jQuery.ajax() or jQuery.when(), you will only want to use the deferred.then(), deferred.done(), and deferred.fail() methods to add callbacks to the Deferred's queues. The internals of the API call or code that created the Deferred will invoke deferred.resolve() or deferred.reject() on the deferred at some point, causing the appropriate callbacks to run.

Huh?!

I found this really good explanation of how exactly jQuery implements Promise (CommonJS Promises/A, mind you!) on top of the $.Deferred object, which makes so much more sense...

From the Top answer to the StackOverflow question: Deferred vs. promise

A deferred object is an object that can create a promise and change its state to resolved or rejected. Deferreds are typically used if you write your own function and want to provide a promise to the calling code. You are the producer of the value.

A promise is, as the name says, a promise about a future value. You can attach callbacks to it to get that value. The promise was "given" to you and you are the receiver of the future value.

You cannot modify the state of the promise. Only the code that created the promise can change its state.

Examples

from StackOverflow

Producer Model

You use deferred objects when you want to provide promise-support for your own functions. You compute a value and want to control when the promise is resolved.

function callMe() {

var d = new $.Deferred();

setTimeout(function() {

d.resolve('some_value_compute_asynchronously');

}, 1000);

return d.promise();

}


callMe().done(function(value) {

alert(value);

});

Forward Model

If you are calling a function which itself returns a promise, then you don't have to create your own deferred object. You can just return that promise. In this case the function does note create a value, but forwards it (kind of):

function fetchData() {

// do some configuration here and pass to `$.ajax`

return $.ajax({...});

}


fetchData().done(function(response) {

// ...

});

Receiver Model (Chaining)

Sometimes you don't want to create or pass along promises/values, you want to use them directly, i.e. you are the receiver of some information:

$('#my_element').fadeOut().promise().done(function() {

// called when animation is finished

});

Of course, what this ultimately means is jQuery's implementation of Promise in Deferred is limited compared with a pure Promise implementation, but in most cases this would probably be sufficient without having to add the overhead of a Promise polyfill, in addition to already loading a jQuery library.