Wait to complete multiple ajax calls which can run concurrently - javascript

I have three ajax calls which can run concurrently. However I want the browser to wait until all ajax calls completed. One way is to set async as false for each of them but then I lose precious time since they can run concurrently. Is there a way to run them concurrently but make the browser hangs until all completed?

After success, call callback function:
$.ajax({
success: function(){ checkAjax(); }
});
And in callback function count how much responses you have.
var totalEnded = 0, totalAjax = 3;
function checkAjax() {
totalEnded++;
if (totalEnded == totalAjax) {
/* Do important stuff here, or call another function */
}
}

If you are using jQuery then have a look at $.when, you can provide a success callback which gets executed when all the requests are finished loading.

To make work with asynchronous stuff easier, you can use the promises pattern. If you're on jQuery, you can use jQuery.when(). From the docs:
$.when( $.ajax( "/p1.php" ), $.ajax( "/p2.php" )).done(function( a1, a2 ) {
//do this when both ajax calls are done
});

You could do this using deferred objects, because ajax itself returns that object. Please refer to Pass in an array of Deferreds to $.when()
var deferreds = [
$.post(),
$.get(),
];
$.when.apply($, deferreds).done(function() {
// All ajax requests was done
});

Related

ASP.NET MVC Action on Synchronous AJAX Requests

I am looking for an MVC implementation equivalent in functionality to the WebForms ajax request handlers below:
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(function());
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function());
A very similar question (link below) was answered with a reference to the global .ajax event handlers, but as all of my calls are synchronous I am having the issue that it is firing the ajax finished event at the end of each individual ajax request, and I want it to start with the first and end when the final one finishes. I tried using ajaxStart and ajaxStop which the documentation suggests should be exactly what I am looking for, but I belive that these would only work as intended with async ajax requests.
(ASP.NET MVC 4 Action on AJAX Request)
Is there any way to do this using the jQuery built in ajax event handlers, or any alternative method for synchronous requests?
You can use jQuery's .when (in combination with .apply) which allows you to execute a callback function based on any number of Deferred objects (which are returned by jQuery .ajax calls). Check out the fiddle and open up dev tools, if you watch the log you will see the correct order of events. First 'started' is logged, then a number of 'ajax response' messages are logged, and finally the 'complete' message is logged at the end of all requests.
Fiddle: http://jsfiddle.net/efjmcm49/
var ajaxCalls = [];
console.log('started');
for(var i = 1; i <= 5; i++){
var currentCall = $.ajax({
url: '/echo/json',
type: 'GET',
success:function(data){
console.log('ajax response');
}
});
ajaxCalls.push(currentCall);
}
$.when.apply($, ajaxCalls).done(function () {
console.log('complete');
});
In a series of synchronous requests, jQuery cannot know when you are done making all of them. How would it know that you aren't just about to start another one?
If the requests are synchronous can't you just use normal program flow? Like:
ajaxStart(); //execute arbitrary code
while(condition) {
//ajax requests here
}
ajaxStop(); //execute arbitrary code
jquery don't have anything inbuilt like that but you can do one thing, take one counter and
initialize with 0 and in each ajaxstart you can increment by 1 and in success/error of ajax
decrement counter by 1 and as soon as you get value of counter as 0 means all request is over.

How to make code wait while calling asynchronous calls like Ajax [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I am looking for something like this
function someFunc() {
callAjaxfunc(); //may have multiple ajax calls in this function
someWait(); // some code which waits until async calls complete
console.log('Pass2');
}
function callAjaxfunc() {
//All ajax calls called here
console.log('Pass1');
}
What I have tried?
1
Jquery.when()
tried using it..it works fine. But not the way I want. $.when will wait but the code next to $.when() runs with out waiting. The code inside do callback only runs after ajax calls
2.
setTimeOut() with a global flag
I was so confident this will work. I tried like following.
GlobalFlag = false;
function someFunc()
callAjaxfunc(); //may have multiple ajax calls in this function
setTimeOut(waitFunc, 100); // some which waits until async calls complete
console.log('Pass2');
}
function callAjaxfunc() {
//All ajax calls called here
onAjaxSuccess: function() {
GlobalFlag = true;
};
console.log('Pass1');
}
function waitFunc() {
if (!GlobalFlag) {
setTimeOut(waitFunc, 100);
}
}​
Still not able to get wanted result. Am I doing something wrong here? This is not the way?
Result I wanted should come like this
Pass1
Pass2
Not able to make any fiddle as it needs AJAX calls
EDIT: As many were suggesting callbacks..i know about them..but still the code next to somewait() will get executed...I want browser to completely stop executing code next to somewait() until the ajax call..Also it may be a bad practice but worth to know and try if possible...
Use callbacks. Something like this should work based on your sample code.
function someFunc() {
callAjaxfunc(function() {
console.log('Pass2');
});
}
function callAjaxfunc(callback) {
//All ajax calls called here
onAjaxSuccess: function() {
callback();
};
console.log('Pass1');
}
This will print Pass1 immediately (assuming ajax request takes atleast a few microseconds), then print Pass2 when the onAjaxSuccess is executed.
Why didn't it work for you using Deferred Objects? Unless I misunderstood something this may work for you.
/* AJAX success handler */
var echo = function() {
console.log('Pass1');
};
var pass = function() {
$.when(
/* AJAX requests */
$.post("/echo/json/", { delay: 1 }, echo),
$.post("/echo/json/", { delay: 2 }, echo),
$.post("/echo/json/", { delay: 3 }, echo)
).then(function() {
/* Run after all AJAX */
console.log('Pass2');
});
};​
See it here.
UPDATE
Based on your input it seems what your quickest alternative is to use synchronous requests. You can set the property async to false in your $.ajax requests to make them blocking. This will hang your browser until the request is finished though.
Notice I don't recommend this and I still consider you should fix your code in an event-based workflow to not depend on it.
Real programmers do it with semaphores.
Have a variable set to 0. Increment it before each AJAX call. Decrement it in each success handler, and test for 0. If it is, you're done.
If you need wait until the ajax call is completed all do you need is make your call synchronously.

jQuery AJAX Result Block Doesn't Fire Immediately

I have a jQuery POST function inside of a loop (multiple post calls).
For some reason, jQuery is posting, but not returning all the data until the loop ends and parsing all the results at once.
FOREACH arg_value IN args
{
console.log('Do stuff');
$.post('https://blah.com/xml.php',
{arg: arg_value},
function(xml) {
$(xml).find('tag').each(function() {
console.log('Do more stuff');
});
});
}
The output of this is...
Do stuff
Do stuff
Do stuff
Do more stuff
Do more stuff
Do more stuff
It seems like jQuery is caching the result or not executing it until the end.
I'm expecting...
Do stuff
Do more stuff
Do stuff
Do more stuff
Do stuff
Do more stuff
Is there an option to tell jQuery to pause execution until there is a result from the AJAX? It appears to be running asynchronously as usual, but I don't want that in this case.
A AJAX call is asynchronous. This means your callback:
function(xml) {
$(xml).find('tag').each(function() {
console.log('Do more stuff');
});
}
Only gets executed when the server returns a response.
Meanwhile, your for-each loop will keep running, and logging Do stuff.
Unless you're doing crazy stuff in your loop, the loop will be faster than the server response
Like Jan Dvorak mentioned, Even if you do crazy stuff, the AJAX callbacks will wait for the loop to finish, resulting in Do stuff always appearing before any of the AJAX responses.
Your ajax call is asyncronous, which means that the ajax call is fired off, then the execution flow of further code continues. It does not wait around for the response. When the response is finally received, the callback is executed.
What you could do is to have your ajax calls all stack up in a queue and as each response is received, fire off the next call in the queue. This would achieve your diesired effect, whereby the next ajax call is not sent until the current one is done.
If you have many calls, this would be much slower than firing them all off as soon as they are needed because browsers can easily handle multiple ajax calls at the same time.
$.post() is async call...will not work in loops the way u want..To get the way u want..here is the solution..
var i=0;
callbackfunc(i) {
console.log('Do stuff');
$.post('https://blah.com/xml.php',
{arg: args[i]},
function(xml) {
$(xml).find('tag').each(function() {
//something related to xml data
});
console.log('Do more stuff');
i++;
if(i<args.length)callbackfunc(i)
}
});
}
take care of variables..may create closures here...
you are asynchronous here, if you want to do that probably the easiest way to achieve this is to use async.js

JavaScript Library to Synchronize Events

let's say I'm doing 3 ajax calls and I want to wait for the 3 calls to finish before doing something.
Is there a library out there to synchronize multiple async events in JavaScript ? (using or not jQuery's event system)
Ex.:
var sync = new syncLib();
$('a1').click(sync.newListener());
$('a2').click(sync.newListener());
sync.wait(function(e1, e2) {
// fired when both a1 and a2 are clicked or when 10 seconds have passed
// e1 and e2 would have properties to know whether or not they timed out or not..
}, 10 /* timeout */));
I have found this one: https://github.com/Ovea/js-sync/blob/master/README.md, but timeouts are not supported. (Let's say the second ajax call takes too long, I don't want my synchronization to be hung up, I want to set a 10 secs timeout)
I know I can code something myself, but I'm just checking here (after googling for it)
Thanks!
EDIT:
Since then I found async: https://github.com/caolan/async
$.when($.ajax("/"), $.ajax("/"), $.ajax("/")).then(function () {
alert("all 3 requests complete");
});
Documentation
you can use jquery deferred object
here is a useful post http://www.erichynds.com/jquery/using-deferreds-in-jquery/
The .deferred, .when, .then solution mentioned in other answers is much more elegant, but it's also possible write your own simple solution just so you see how this can be done manually. You just set a counter for how many ajax calls you have in flight and in the success handler for each ajax calls, you decrement the counter and fire your action when the counter gets to zero.
function DoMyAjaxCalls(callbackWhenDone) {
var numAjaxCalls = 3;
// set timeout so we don't wait more than 10 seconds to fire the callback
// even if ajax calls aren't done yet
var timer = setTimeout(callbackWhenDone, 10*1000);
function checkAjaxDone() {
--numAjaxCalls;
if (numAjaxCalls == 0) {
clearTimeout(timer);
callbackWhenDone();
}
}
// first ajax call
$.ajax({
url: 'ajax/test1.html',
success: function(data) {
// write code to handle the success function
checkAjaxDone();
},
error: checkAjaxDone
});
// second ajax call
$.ajax({
url: 'ajax/test2.html',
success: function(data) {
// write code to handle the success function
checkAjaxDone();
},
error: checkAjaxDone
});
// third ajax call
$.ajax({
url: 'ajax/test3.html',
success: function(data) {
// write code to handle the success function
checkAjaxDone();
},
error: checkAjaxDone
});
}
Here you have a [library][1] based on jQuery made for that purpose.
In simple use-cases, $.when() is BEST but jcon-q-rency allows you to synchronize any asynchronous code sections.
http://www.megiddo.ch/jcon-q-rency

Waiting on multiple asynchronous calls to complete before continuing

So, I have a page that loads and through jquery.get makes several requests to populate drop downs with their values.
$(function() {
LoadCategories($('#Category'));
LoadPositions($('#Position'));
LoadDepartments($('#Department'));
LoadContact();
};
It then calls LoadContact(); Which does another call, and when it returns it populates all the fields on the form. The problem is that often, the dropdowns aren't all populated, and thus, it can't set them to the correct value.
What I need to be able to do, is somehow have LoadContact only execute once the other methods are complete and callbacks done executing.
But, I don't want to have to put a bunch of flags in the end of the drop down population callbacks, that I then check, and have to have a recursive setTimeout call checking, prior to calling LoadContact();
Is there something in jQuery that allows me to say, "Execute this, when all of these are done."?
More Info
I am thinking something along these lines
$().executeAfter(
function () { // When these are done
LoadCategories($('#Category'));
LoadPositions($('#Position'));
LoadDepartments($('#Department'));
},
LoadContact // Do this
);
...it would need to keep track of the ajax calls that happen during the execution of the methods, and when they are all complete, call LoadContact;
If I knew how to intercept ajax that are being made in that function, I could probably write a jQuery extension to do this.
My Solution
;(function($) {
$.fn.executeAfter = function(methods, callback) {
var stack = [];
var trackAjaxSend = function(event, XMLHttpRequest, ajaxOptions) {
var url = ajaxOptions.url;
stack.push(url);
}
var trackAjaxComplete = function(event, XMLHttpRequest, ajaxOptions) {
var url = ajaxOptions.url;
var index = jQuery.inArray(url, stack);
if (index >= 0) {
stack.splice(index, 1);
}
if (stack.length == 0) {
callback();
$this.unbind("ajaxComplete");
}
}
var $this = $(this);
$this.ajaxSend(trackAjaxSend)
$this.ajaxComplete(trackAjaxComplete)
methods();
$this.unbind("ajaxSend");
};
})(jQuery);
This binds to the ajaxSend event while the methods are being called and keeps a list of urls (need a better unique id though) that are called. It then unbinds from ajaxSend so only the requests we care about are tracked. It also binds to ajaxComplete and removes items from the stack as they return. When the stack reaches zero, it executes our callback, and unbinds the ajaxComplete event.
You can use .ajaxStop() like this:
$(function() {
$(document).ajaxStop(function() {
$(this).unbind("ajaxStop"); //prevent running again when other calls finish
LoadContact();
});
LoadCategories($('#Category'));
LoadPositions($('#Position'));
LoadDepartments($('#Department'));
});
This will run when all current requests are finished then unbind itself so it doesn't run if future ajax calls in the page execute. Also, make sure to put it before your ajax calls, so it gets bound early enough, it's more important with .ajaxStart(), but best practice to do it with both.
Expanding on Tom Lianza's answer, $.when() is now a much better way to accomplish this than using .ajaxStop().
The only caveat is that you need to be sure the asynchronous methods you need to wait on return a Deferred object. Luckily jQuery ajax calls already do this by default. So to implement the scenario from the question, the methods that need to be waited on would look something like this:
function LoadCategories(argument){
var deferred = $.ajax({
// ajax setup
}).then(function(response){
// optional callback to handle this response
});
return deferred;
}
Then to call LoadContact() after all three ajax calls have returned and optionally executed their own individual callbacks:
// setting variables to emphasize that the functions must return deferred objects
var deferred1 = LoadCategories($('#Category'));
var deferred2 = LoadPositions($('#Position'));
var deferred3 = LoadDepartments($('#Department'));
$.when(deferred1, deferred2, deferred3).then(LoadContact);
If you're on Jquery 1.5 or later, I suspect the Deferred object is your best bet:
http://api.jquery.com/category/deferred-object/
The helper method, when, is also quite nice:
http://api.jquery.com/jQuery.when/
But, I don't want to have to put a bunch of flags in the end of the drop down population callbacks, that I then check, and have to have a recursive setTimeout call checking, prior to calling LoadContact();
No need for setTimeout. You just check in each callback that all three lists are populated (or better setup a counter, increase it in each callback and wait till it's equal to 3) and then call LoadContact from callback. Seems pretty easy to me.
ajaxStop approach might work to, I'm just not very familiar with it.

Categories