1252748
1252748

Reputation: 15369

multiple done()s in a jquery deferred -- how does it work?

Recently I asked about how I could trigger a variable number of jquery get() requests and I received this code as a really efficient working solution:

var d = new $.Deferred();
var promise = d.promise();
var results = [];
for (var i = 0; i < 5; i++) {
    (function(i) {
        promise = promise.then(function() {
            return $.ajax('/echo/json/', {
                data: {
                    json: JSON.stringify({foo: i})
                }
            }).done(function(data) {
                results[i] = data;
            });
        });
    }(i));
}

promise.done(function() {
    console.log(results);
});

d.resolve(); 

fiddle

I'm looking for an explanation of how exactly this works with the multiple done()s attached to each promise.then(), and then the final done() attached to the promise itself. Is it that a promise (from what I understand is a special type of sort of deferred itself) can have a done, then the deferred itself can also have a done? If it weren't in a loop, what would this syntax look like for, say, three ajax requests in a row? Just trying to get my head around it. Thanks!

Upvotes: 3

Views: 6755

Answers (2)

danielrsmith
danielrsmith

Reputation: 4060

If you have an array of deferred objects you can actually deal with them using when and apply to get the promises and then use $.done() on them:

$.when.apply($, deferredArray).done(function() {
   for (var i = 0; i < arguments.length; i++) {
      //arguments[i] is the return of the singular done() statement    
   }
});

This works rather well when you don't know how many deferred objects you are working with.

Upvotes: 7

Fabian Schmengler
Fabian Schmengler

Reputation: 24576

A promise is a wrapper for the deferred that hides the resolve and reject methods, kind of the public interface of the deferred. For then() and done() it makes no difference if you use them on a deferred or on its promise. I'll use the term deferred for both from now.

That being said, done() returns the deferred itself which allows chaining. You can add as many done (and fail) handlers as you want like that. They will be called one by one.

then() returns a new deferred*, which can have its own done and fail handlers.

Note that in your code you replace the deferred in the promise variable on each loop iteration, so the final done() is not called on the original deferred but on the latest, returned by the last then().

All calls chained in one line would look like that (each then() returns a new promise. I marked, on which the done() methods are called):

d.then().done().then().done().then().done().then().done().done();
         ^^^^^^        ^^^^^^        ^^^^^^        ^^^^^^^^^^^^^
        promise 1     promise 2     promise 3       promise 4

*) actually its promise

Upvotes: 3

Related Questions