0

I have the following parameters:

a = [{param:'a'}, {param:'b'}, {param:'c'}]

I'd like to make a get request for each parameter, like this:

a.map(function(ai){return $.get('myapi/get?ai='+ai.param)})

How do I do something once all the get requests have finished?

I have tried using $.when, like this:

$.when(
    a.map(function(ai){return $.get('myapi/get?ai='+ai)})
)
.done(function(results){
    results.forEach(function(ri, i){
        ri.success(function(result){
            a[i].result = result
        }
    }
    do_something_with(a)
}

unfortunately I am clearly misunderstanding this $.when().done() idiom as when I call do_something_with(a) I don't have the new .result attribute. I'm guessing it's because when is seeing a single array and so just passes straight into the .done(), as opposed to waiting for each component get to finish.

Any help would be appreciated!

Mike Dewar
  • 10,945
  • 14
  • 49
  • 65
  • What is `ri.success` supposed to be? `ri` is the result returned by the AJAX call (or would be, if not for other errors in the code), not a deferred/`jqXHR` object. – Tgr Apr 27 '12 at 21:10

1 Answers1

2

You need:

$.when.apply($, myArray);

i.e. using Function.apply to call $.when() with this === $ and the rest of the arguments being the contents of the array myArray, where that array contains the deferred objects returned by each call to $.get.


To answer the second question from your comments, you could pass your array of deferred objects through this map function, which returns a new array of deferred objects which will be resolved at completion of each AJAX call, regardless of whether it succeeded or not.

var alwaysDef = def.map(function(old) {
    var def = $.Deferred();
    old.always(def.resolve);
    return def;
});

Note that I'm not sure what parameters (if any) will end up being passed to the final .done function in this instance.

If that matters, the deferred objects are always called in order, so you can register a .done handler for each of the original promises that stores the AJAX results in an array for later use, and a .fail handler that stores a null value instead.

That will ensure that your final .when handler isn't invoked until after each of the individual results are available to you.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • that was FAST! I use the same trick when dealing with the response in .done()? – Mike Dewar Apr 27 '12 at 20:26
  • @MikeDewar in `.done()` you'll need to use the `arguments` pseudo-array to retrieve the response data - AFAICR one for each AJAX call. – Alnitak Apr 27 '12 at 20:29
  • use console.log(arguments) within the done callback to see what the arguments contain. It should be an array of objects or arrays. – Kevin B Apr 27 '12 at 20:55
  • is there an approach that doesn't mind terribly if one or more of the promises fails? Seems like .done and .then are both quite sensitive to a failed response – Mike Dewar Apr 27 '12 at 23:34
  • @MikeDewar yes - you have to create a new `Deferred` for each request that you `.always()` `.resolve()` and then go do your stuff only `.when()` _those_ deferred objects are all `.done`. ;-) – Alnitak Apr 27 '12 at 23:56