2

I've read something about deferred and promises, but I still don't know how I can manage that.

for(...){//we don't know the number of ajax calls
   $.ajax({...});
}

if(all the ajax call we made are done){...}

The point is that I need to keep "ajax.async = true".

Donovant
  • 3,091
  • 8
  • 40
  • 68
  • For not daring to suggest `async: false` +1.. *that way lays the dark side*. – iCollect.it Ltd Sep 01 '15 at 15:06
  • @Bergi: Worth noting that the duplicate question you chose, to close this one with, is *not* a good match to this question. You need to pick one that requests a *variable number of promises*, not just multiple promises. – iCollect.it Ltd Sep 01 '15 at 16:18
  • @TrueBlueAussie: Actually the accepted answer of the dupe has a paragraph for "*If you don't know in advance how many ajax arguments you need to wait for …*". But you're right, I might should've picked [How do you work with an array of jQuery Deferreds?](http://stackoverflow.com/q/4878887/1048572) directly – Bergi Sep 01 '15 at 17:40

1 Answers1

4

The traditional way:

The traditional way to solve this is to add the promises to an array, then evaluate them all together using $.when.apply

var promise = [];
for (var i = 0; i < 6; i++){
    promise.push(delay(10-i, $('#' + i)));
}
$.when.apply($, promise).done(function(){
    alert("All done");
});

JSFiddle: http://jsfiddle.net/TrueBlueAussie/rgj0bx95/1/

Working with returned values:

As you want to keep the values, you can then access them using the arguments array:

var promise = [];
for (var i = 0; i < 6; i++){
    promise.push(delay(6-i, $('#' + i)));
}
$.when.apply($, promise).done(function(){
    $('body').append("All done!");
    for (var i = 0; i < arguments.length; i++){
        $('body').append(arguments[i]).append("<br/>");
    }
});

Example:

The following example uses a simple function that returns a promise, using a timer, to simulate ajax calls. It clearly shows the suggestion working even though the promises complete in "random" order (just to demonstrate):

JSFiddle: http://jsfiddle.net/TrueBlueAussie/rgj0bx95/5/

Notes:

  • The values are returned in the order the calls were made, not the completion order.

Other methods

Little trick I found: You can chain promises in parallel with $.when without having to use an array of promises:

var promise;   // Undefined also means a resolved promise to $.when
for(...){//we don't know the number of ajax calls
   promise = $.when(promise, $.ajax({...}));
}
promise.done(function(){
   alert("All done");
});

Notes:

  • I figured this one out after seeing someone chain promises sequentially, using promise = promise.then(newpromise)
  • The downside is it creates extra promise objects behind the scenes and any parameters passed at the end are not very useful (as they are nested recursively inside additional objects). If you do not require the parameters, it is short and simple.

You will note in the following fiddle that the results are nested and in the reverse order you want them. Again this technique is only useful if you do not want the results of the promises (which is quite often for parallel operations).

Summary: The $.when technique is only useful if you do not care about the result values.

JSFiddle: http://jsfiddle.net/TrueBlueAussie/rgj0bx95/9/

iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
  • So your solution is to run the ajax calls sequentially? – Jaromanda X Sep 01 '15 at 14:50
  • Oh, I misread the `$.when` as `$.then` - my mistake (thought `$.then` was some more jQuery bastardisation of the promise spec) - the question asks _how can I **use the results** of ajax calls_ - seems your solution throws all the results away – Jaromanda X Sep 01 '15 at 14:54
  • @JaromandaX: Have added answer that includes processing a variable number of results. – iCollect.it Ltd Sep 01 '15 at 15:24
  • Only one question: why did you use delay() function? What's for? Maybe to simulate several ajax calls, sorry mate. Thanks. – Donovant Sep 01 '15 at 19:56
  • As I mention in the answer `"uses a simple function that returns a promise, using a timer, to simulate ajax calls"`. It just simulates async events in a way we can watch. Harder to show with Ajax calls, but a *promise is a promise* ;) – iCollect.it Ltd Sep 01 '15 at 19:58
  • 1
    I think the bug is rather `arr= arguments[0];` which should have been `arr= arguments;`. Using `promise = $.when(promise, undefined);` is a really odd way to fix that… – Bergi Sep 02 '15 at 12:43
  • @Bergi: You are correct. I will update. Stupid mistake :) – iCollect.it Ltd Sep 02 '15 at 12:44