0

Why does the code under the done() statement execute before the other 3 function which are called under when()? It goes immediately. I thought when was used to queue up functions and done was used to execute something when the when code was, well, done...

$(document).on('click', '.ajax', function() {
    $.when(func1('<p>first</p>'), func2('<p>second</p>'), func3('<p>third</p>')).done(function() {
        $('body').append('all done');
    });
});

function func1(first) {

    var t = setTimeout(function() {
        $('body').append(first);
    }, 800);
    return "success";

}

function func2(second) {

    var t = setTimeout(function() {
        $('body').append(second);
    }, 2700);
    return "success";
}

function func3(third) {

    var t = setTimeout(function() {
        $('body').append(third);
    }, 200);
    return "success";
}​

http://jsfiddle.net/loren_hibbard/NhAFN/

1252748
  • 14,597
  • 32
  • 109
  • 229
  • 3
    You know that those functions are returning `"success"` almost instantaneiously right? `setTimeout` runs ansychronously. – thatidiotguy Nov 16 '12 at 20:41
  • @thatidiotguy but if I change to `return t;` or take out the return statement altogether, the same thing happens... http://jsfiddle.net/loren_hibbard/NhAFN/1/ – 1252748 Nov 16 '12 at 20:45
  • Correct. What is the question? I am telling you that your code is not waiting for the "timeout" amount before returning something. – thatidiotguy Nov 16 '12 at 20:47
  • @thatidiotguy I'm trying to understand how to make the `done()` function not get called until all functions in the "queue" (if that is what it even is) are complete. – 1252748 Nov 16 '12 at 20:49
  • http://jsfiddle.net/NhAFN/2/ – Yury Tarabanko Nov 16 '12 at 20:50
  • `when()` accepts `Deferred` or `Promise` objects, when you pass it strings ("success") it just runs like regular javascript. – jbabey Nov 16 '12 at 20:57

1 Answers1

5

You need to use $.Deferred() and return promise.

function func1(first) {
    var dfd = $.Deferred();

    var t = setTimeout(function() {
        $('body').append(first);
        dfd.resolve();
    }, 800);
    return dfd.promise();

}

http://jsfiddle.net/NhAFN/2/

Yury Tarabanko
  • 44,270
  • 9
  • 84
  • 98
  • First off, thanks, this is exactly what I was looking for. If I have some named functions that make ajax calls, can I add the deferred promise to the function without interrupting its functionality in situations in which it is not called by `$when()` If that makes sense.. – 1252748 Nov 16 '12 at 20:59
  • You can just return the result of ajax function call. `function myAjax() { return $.ajax(...);}` – Yury Tarabanko Nov 16 '12 at 21:00
  • okay so like `function populate dropdown(d){ return $.ajax({....success:function(){...} });` where would I put the `dfd.resolve();` and `dfd.promise();` objects? Assuming that I just put the `var dfd = $.Deferred();` at the top of the function. – 1252748 Nov 16 '12 at 21:03
  • 1
    @thomas If you are using `return $.ajax()` you don't need `var dfd = ...` and you don't need to resolve it, that part is done for you by `$.ajax` – Kevin B Nov 16 '12 at 21:05
  • The jqXHR objects returned by $.ajax() as of jQuery 1.5 implement the Promise interface, giving them all the properties, methods, and behavior of a Promise... – Yury Tarabanko Nov 16 '12 at 21:08
  • yeah, i've got the return $.ajax, but when I do this: `$.when(populate_sector_dropdown('sector_dropdown_1')).done(function() { var new_sector_clone = $('#sector_1').clone(); console.log(new_sector_clone); });` in the console, the object that i've cloned doesn't have the dropdown that's been populated by the ajax, which makes it seem like the clone is getting made before the ajax is done. ie, not waiting till `done()` somehow. any ideas what this could be? Thanks again for your help. – 1252748 Nov 16 '12 at 21:08
  • hmm..well, i'm definitely linked to `http://code.jquery.com/jquery-latest.js`. Do you see any problems with that code? – 1252748 Nov 16 '12 at 21:22
  • Could you please provide a fiddle with `populate_sector_dropdown` function. And btw I do recommend you to read this article about deferred objects, pipes, etc: http://sitr.us/2012/07/31/promise-pipelines-in-javascript.html – Yury Tarabanko Nov 16 '12 at 21:30
  • http://jsfiddle.net/loren_hibbard/KDG4R/ will read article now. thank you for taking a look. – 1252748 Nov 16 '12 at 21:37
  • It seems that your success function is actually making another ajax request to load template. You definitely need to read the article to figure out how to create a chained deferred. – Yury Tarabanko Nov 16 '12 at 21:45
  • hmm. yeah, I guess it would be to use that template. Never rains but it pours :( Thanks for your tremendous help! – 1252748 Nov 16 '12 at 21:49