1

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?

2
  • Have you popped open the developer console to check for any errors? Commented May 30, 2015 at 1:35
  • no errors, but strangely, first console.log ( replaced alert and url for run in browser) output has doubled. W.T.H.? Commented May 30, 2015 at 11:55

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. I see where my fault is
1

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

Comments

0

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.

5 Comments

Great, now i saw things clearly, special thanks for suggested solution which facilitates understanding of a subject and saves me from weekend's headache
But...) there's still one thing seem unclear to me. I noticed that you used .then() for assigning callbacks instead of .done(). I run your code ( worked perfectly, thanks again) unchanged except using .done instead of .then here: **return $.ajax("/echo/json/").done(function() { which results in immediate execution of 2nd callback ("after timer"), as if it was assigned to already resolved deferred object.
I use .then() because it is the promise standard way of doing things, not a jQuery invention.
thank you, so it looks like .done() is not useful for chaining promises
@PaulJanssen - yes, only .then() supports full-borne chaining by returning new promises from within the callbacks. Once you learn how .then() works in standards-compliant promises, I've found no reason to ever use .done() with jQuery again. Plus, I see value in coding the standards-compliant way (when possible) which is to use .then().

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.