Reputation: 4898
I'd like to write a function which performs a dozen async ajax requests, wait for all of then to finish and then return aggregated info. Like:
function countHealthy(urls) {
var healthy = 0;
for (var i = 0; i < urls.length; ++i) {
$.ajax({url: urls[i], async: true, id: i})
.done(function (data) { ++healthy; });
}
// Wait for all ajax to finish.
return healthy;
}
PS: Is the ++healthy thread safe?
Upvotes: 6
Views: 9725
Reputation: 1
First of all you are making an ajax request on each for loop which seems a bit wasting your server resources. If that function will be getting called a lot then i would suggest you to refactor your code to make as less queries as possible.
Anyways, here's how i'd do it
function countHealthy(urls) {
var healthy = 0;
var reqs = [];
for (var i = 0; i < urls.length; ++i) {
reqs.push(
$.ajax({
url: urls[i],
id: i
})
);
}
}
$.when.apply($, reqs).then(function() {
// On success
++healthy;
}).fail(function() {
// When failed
}).always(function() {
// this will be run no matter the outcome
});
Haven't had the chance to try it out, so i'm not sure if i've made a syntax error etc. Changes to your piece of code :
Removed async = true
, ignore this if you had set it to be false somewhere in your code before.
You can get an idea of how "when.apply" works, source
Upvotes: 0
Reputation: 2112
If you have a complex page, you will want to track and wait specifical for just your asynchronous calls to return. This is because other, non-crucual, calls might be running.
That being said, for simple pages you can just check and wait for there to be no calls. This jQuery script checks every quarter to see if there are current asynchronous requests every quarter second. Once there are none, you will proceed.
var WaitForAjax = function()
{
if (jQuery.active == 0){
}
else
{
setTimeout(WaitForAjax, 250);
}
}
function RunIt()
{
//IssueAjaxCalls would be where you make all your Ajax calls.
IssueAjaxCalls();
WaitForAjax();
//The KeepGoing function won't get called until there are no more Ajax calls pending.
KeepGoing();
}
Upvotes: 0
Reputation: 3281
Maybe you can try this. I'm simply running an empty while loop so that the return statement is not hit until all the ajax calls are returned.
function countHealthy(urls) {
var healthy = 0;
var urlCount = urls.length;
var numberOfAjaxCallsReturned = 0;
for (var i = 0; i < urls.length; ++i) {
$.ajax({url: urls[i], async: true, id: i})
.done(function (data) {
++healthy;
numberOfAjaxCallsReturned++;
});
}
while(numberOfAjaxCallsReturned!=urlCount)
{
}
return healthy;
}
Upvotes: 0
Reputation: 120198
Javascript doesn't have threads so thread safety is not an issue. Your return statement is the problem, it needs to go in the callback that the ajax calls execute on completion. Since ajax happens asynchronously, as your code stands, the return statement will fire before all the requests return.
You might want to check out query deferreds, which seems to be born for this type of thing. Directly from that link
function doAjax() {
return $.get('foo.htm');
}
function doMoreAjax() {
return $.get('bar.htm');
}
$.when( doAjax(), doMoreAjax() )
.done(function() {
console.log( 'I fire once BOTH ajax requests have completed!' );
})
.fail(function() {
console.log( 'I fire if one or more requests failed.' );
});
With some minor refactoring you could implement this in about 2 minutes.
Alternatively, if you control the server, you could create a server endpoint that does all the checking in one request.
Upvotes: 6
Reputation: 11721
You can do this:
var urls= ['url1', 'url2', 'url3', 'url4'];
function doTheUrl() {
if (urls.length === 0) {
alert('All urls are done now.');
return;
}
var url = urls.pop();
$.ajax({
url: "/DoTheJob",
complete: function () {
doTheUrl();
}
});
};
Upvotes: 1