Click to change color scheme

Notes on codes, projects and everything

Latest Post

Deferred and Promise in jQueryland

Catching up with all the new toys in web-development, has gotta be the worst nightmare one can ever have. While not paying attention to the web-development field of work, there are quite a number of new things popping up here and there. One of them is Promise introduce in ES6. However, before I get into that (likely never), I would like to start from jQuery first as I still rely on it for a lot of work.

Apparently starting from jQuery 3, they implemented Promise that is compliant with Promise/A+ specification. The same specification is also used to implement the native ES6 promise.

While I understand mostly what it is trying to achieve (Shadow DOM OTOH….), I couldn’t wrap my head around the difference between a Deferred object and a Promise object in jQuery. While jQuery updated the implementation of Promise, it doesn’t seem to update the API doc thoroughly enough (but most probably I can’t read properly).

So this post is an attempt to jot down some notes on the differences between the two. They might not be correct, but should be good enough to start.

An example usage of a Deferred object is

var f = function() {
    var d = $.Deferred();

    setTimeout(d.resolve, 2000)

    return d
}

f().then(function() {
    console.log(arguments) // returns []
    console.log('hello world')
})

So in this case the function f will start the chain of fulfillment handlers (we only have one here) after roughly 2 seconds. The Javascript developer console should show an empty list, as well as a message ‘hello world’.

One thing we can do with a Deferred object is that we can mess around with it. For example, preempt to start the fulfillment (or rejection) chain prematurely (before the 2 second timer ends). For example, we can pass in a random number 10 into the first fulfillment handler, as follows.

f().resolve(10).then(function() {
    console.log(arguments) // returns [10]
    console.log('hello world')
})

The console should print an array with one element 10 as well as the ‘hello world’ message immediately before the timer ends.

Now we look at Promises

var f = function() {
    var d = $.Deferred();

    setTimeout(d.resolve, 2000)

    return d.promise()
}

f().then(function() {
    console.log(arguments) // returns []
    console.log('hello world')
})

The snippet is essentially identical to the first one above, except this time I am returning a jQuery Promise object. As both Deferred and Promise object have more or less the same properties the code still runs. In fact the methods provided by a Deferred object is a superset of a Promise object.

Unlike a Deferred object, we do not get to play around with a Promise, i.e. no preemption.

f().resolve(10) // TypeError, resolve is not a function
    .then(function() {
        console.log(arguments) // returns []
        console.log('hello world')
    })

As seen in the development console, running the snippet above yields a TypeError as resolve is not defined as a property of the promise object returned by f().

Usually people associate a Promise object with the term Consumer. I suppose that’s because one don’t get to modify the promise for whatever reason. The only thing one can do is to add handlers to the fulfillment / rejection chain. However, it looks like it is possible to modify a Deferred object to certain degree. This is probably the reason why people associate a Deferred object with the term Producer.

There’s also .done() vs .then() as well as .fail() vs. .catch(). My understanding of them is .done() (or .fail()) is a series of .then() (or .catch() OTOH) chained together. As Promise/A+ has a different way of choosing handlers .fail() and .done() shouldn’t be used to minimize unpleasant surprises. Also they are not part of the official native implementation so should be ignored.

Leave a comment

Other new Posts