Landon Landon - 3 months ago 8
jQuery Question

multiple ajax calls wait for last one to load, then execute

I have multiple ajax queries running at the same time, and I want them to wait for the last one to return, and then run the success handler on all of the ajax calls. For a simplified example, consider:

$.ajax({//ajax call 1
url:page1.php,
success: function(data1){
//do something with data1
}
});

....

$.ajax({//ajax call 2
url:page2.php,
success: function(data2){
//do something with data2
}
});
//consider more than just two concurrent requests


Let's say that all of the requests are sent off at the same time. As they are asynchronous, they will return at different times. Let's say one request takes 100ms to return and the other request takes 3000 ms to return. I obviously don't know which one will return first or last. They all update the DOM in some manner and I want those changes shown to the viewer all at once on one update. How do I do this?

The best I can think of is to save data1 and data2 as global variables. And then have a counter variable that counts every time a success is returned. Then, upon counter==TOTAL_NUM_REQUESTS call a function like updateAll(), then runs through all of the global variables and puts them where they need to go. But this seems messy and prone to errors. Plus that would be a lot of global variables.

What I ideally want is to have the success handlers sleep upon returning, and then on my condition of counting all of them as returned, send wake up messages to all of them and they can resume executing. This seems the cleanest, but I'm not aware of any functionality like this in javascriptland.

Does anybody have any slick ideas for this?

ANSWER UPDATE

Thanks to Lee below, I was able to get a solution. My solution looked similar to his below. I build a list of
async
variables that were assigned to the $.ajax call. Initially the success handler of those ajax calls were still being called, so I removed them and put them in another function that was to be subsequently called by this
when
block I wrote. I passed
results
in to the function like this:

var results = [];
results.push(async1);
results.push(async2);
... for all the results ...

$.when.apply(this, results).done(function() {
for(var i=0;i<arguments.length;i++){
dataobject=arguments[i][0]
if(dataobject.variousattribute)
mySuccessHandlerFirstGuy(dataobject)
else if(dataobject.anotherattribute)
mySuccessHandlerSecondGuy(dataobject)
//etc ....
}
};


The arguments object took a little work to figure out what it was. It was a 2d array (list of lists). The first index represented the returned object corresponding to a given ajax request. It seems to be in order, but it would be best to have your server return something that you can look for and write an if/else block accordingly. Then, in that given element, there appears to be 3 elements within that list. The first being the value that was returned from the server, ie what you want. The second was always a string
success
, which you can presumably use to check if the call worked. And the third element in that list seems to be the initial request (though I'm not sure). This was of no use to me.

Anyway, I hope this helps somebody in the future. And thanks again to Lee to point me in the correct direction.

Answer

Use the jQuery $.when() function to run something when all the ajax calls finish:

jQuery.when docs

var async1 = $.ajax({//ajax call 1
    url:page1.php,
    success: function(data1){
        //do something with data1
    }
});

....

var async2 = $.ajax({//ajax call 2
    url:page2.php,
    success: function(data2){
        //do something with data2
    }
});

$.when(async2, async1).done(function(result2, result1) {
    ... do this when both are successful ...
});

Added in response to questions:

If you have a bunch of ajax calls you can use 'apply' like this:

var results = [];
results.push(async1);
results.push(async2);
... for all the results ...

$.when.apply(this, results).done(function() {
    ... use 'arguments' array to get results ...
});