patryk
patryk

Reputation: 651

Returning a promise from within a deferred's callback

I am working on some anync stuff and I really want to implement that in a good manner.

Consider following code

function getData(latency) {
    var deferred = $.Deferred();

    window.setTimeout(function () {
        deferred.resolve(Math.random());
    }, latency + 100);

    return deferred.promise();
}
function getSpecialData() {
    var deferreds = [];
    for (var i = 0; i < 3; i++) {
        deferreds.push(getData(1000 * i));
    }
    return $.when.apply($, deferreds);
}

function log(msg) {
    $("#console").append("<li>" + msg + "</li>");
    console.log(msg);
}

getData(3000)
.done(function () {
    log("got 3000 data");
    return getSpecialData()
    .done(function () {
        log("got special data");
    });
})
.always(function () {
    log("got all data");
});

As you can see, I am returning a promise from within both getData and getSpecialData functions. I am also chaining calls to these functions the way you see. What is more, I am returning a promise from within the getData done callback.

I have been expecting that the deferred object cares about what its callbacks return and if it's a promise, wait for that promise to resolve and then another callback. What is actually happening is that it doesn't care about what I am returning from within the callback. The order is:

  1. Call getData, after 3s get the "got 3000 data" info,
  2. at the same time fire getSpecialData and the always callback with "got all data" message

What I want to achieve is the following order of function calls:

  1. Call getData, after 3s get the "got 3000 data" information,
  2. call getSpecialData, after 3s get the "got special data" information,
  3. immediately after "got all data" message.

What is the best approach to make it work the way I want?

Upvotes: 0

Views: 845

Answers (2)

Bergi
Bergi

Reputation: 664464

You cannot return anything from a callback, because that's meaningless - the result is not used anywhere in the caller, it's type is effectively void.

To chain actions, you can use then instead of done. The method will return a promise for the (async) result of the callback, which can itself be a promise.

Upvotes: 0

SLaks
SLaks

Reputation: 887413

That's exactly what .then() (or .pipe() before jQuery 1.8) does.

Call that instead of .done().

Upvotes: 1

Related Questions