Paul Janssen
Paul Janssen

Reputation: 13

Unexpected deferred object's behaviour

Could anyoune please clarify what's wrong with the code below ( have read a lot of docs and examples, but still got no idea what's going on)

function t() {
    var d = $.Deferred();
    setTimeout(function(){
        d.resolve();
    }, 5000);
    return d.promise();
}
function test() {
    var dd = $.Deferred();
    $.ajax("/echo/json/").done(function() {
        dd = t();
        dd.done(function() { alert(" dd.done inside ajax")});
    });
    dd.done(function() { alert(" dd.done outside ajax")});
}
test();

the output was (in ~ 5 s):

"dd.done inside ajax:"

Why second .done is not working?

Upvotes: 1

Views: 56

Answers (3)

jfriend00
jfriend00

Reputation: 707218

Your second alert is never called because the original deferred you assign to the variable dd is never resolved and thus its .done() handler is never called.

You create a deferred and assign it to dd here:

var dd = $.Deferred();

And, then you set up a .done() handler with this:

dd.done(function() { alert(" dd.done outside ajax")});

But, when your ajax function finishes, you assign a different promise to the variable dd with this line:

dd = t();

And, thus nothing ever resolves the original promise so its .done() handler is never called.


I'd suggest this design instead:

function t() {
    var d = $.Deferred();
    setTimeout(function(){
        d.resolve();
    }, 5000);
    return d.promise();
}
function test() {
    return $.ajax("/echo/json/").then(function() {
        console.log("ajax call done");
        return t();
    }).then(function() {
        console.log("after timer");
    });
}

test().then(function() {
    console.log("everything done");
});

Working demo: http://jsfiddle.net/jfriend00/atafc5hj/

This illustrates the following concepts which are useful to know:

  1. Using the promise already returned from $.ajax() rather than creating your own.
  2. Chaining another activity to that promise.
  3. Returning another promise from the .then() handler to make the sequence wait for that promise too.
  4. Returning the chained promise from the main function so you can see when everything is done.

Upvotes: 0

Pointy
Pointy

Reputation: 413702

Let's look at test():

function test() {
    var dd = $.Deferred();
    $.ajax("/echo/json/").done(function() {
        dd = t();
        dd.done(function() { alert(" dd.done inside ajax")});
    });
    dd.done(function() { alert(" dd.done outside ajax")});
}
test();

Local variable dd is initialized to a new jQuery Deferred object. Then, an ajax operation is started, and given a "done" callback that'll call the other test function t().

The $.ajax() call will return essentially immediately, long before its .done() callback is run. Right after that, another .done() callback is established for that Deferred instance created at the beginning of the function.

Now, when the ajax "done" callback runs, the value of dd — the initially-created Deferred object — will be overwritten with the Promise returned from t(). Eventually that .done() callback will be run, but nothing ever resolves the first Deferred instance, so that "outside" callback never happens.

Upvotes: 2

Ram
Ram

Reputation: 144669

Because that deferred object is not resolved. You are creating 2 deferred objects and resolving one of them.

Upvotes: 1

Related Questions