I have 2 questions:
1- How do I set a delay when an ajax post is executing many times ?
2 -How to run some_multi_ajax_function() when the variable exe_counter reaches 0 ?
here is my code:
for (i = 0; i < some_data_list.length; i++) {
exe_counter=1;
data = some_data_list[i];
// Many ajax posts will be executed here. In the end exe_counter will be set to 0;
some_multi_ajax_function(data);
}
function some_multi_ajax_function(data){
$.ajax({
...
}.done(function(d) {
// here it could be used another ajax function
exe_counter = 0;
});
}
UPDATE
I am sorry, I have bad explained.
I want execute
data = some_data_list[1]; // second iteration. after that and others
some_big_function(data); // this can't start if exe_counter != 0
when exe_counter==0 its mean that some_multi_ajax_function() is completely done.
Here you have the answer to the first question:
Execute script after specific delay using JavaScript
Now for the 2nd question, there are several problems with your code:
To call the same function when it reaches 0 would create an infinite loop.
exe_counter isn't changed at the end. It will be changed when the first ajax return in the example you gave.
You should set exe_counter outside the loop, and assing to it the value of some_data_list.length
then in some_multi_ajax_function you do exe_counter--;
then you test for 0 and call the function which you want to call on finalization but this function can't be some_multi_ajax_function()
so it goes like this:
exe_counter = some_data_list.length;
for (i = 0; i < some_data_list.length; i++) {
data = some_data_list[i];
// Many ajax posts will be executed here. In the end exe_counter will be set to 0;
some_multi_ajax_function(data);
}
function end_function() {
// whatever
}
function some_multi_ajax_function(data){
$.ajax({
...
}.done(function(d) {
// here it could be used another ajax function
exe_counter--;
if (exe_counter == 0) end_function();
});
}
This is untested code just to explain the concepts. Also try not to use global variables (the ones without var clause). They make your code messy and hard to maintain.
You question isn't very clear but it sounds like you want to use when to manage the ajax requests rather than have them all nested. You can pass an array of ajax promises into when by using the apply method.
// this function returns a promise
function some_multi_ajax_function(data){
return $.ajax({
// ...
});
}
function getPromises() {
for (var i = 0; i < some_data_list.length; i++) {
var promises = [];
exe_counter = 1;
var data = some_data_list[i];
// push all promises into an array
promises.push(some_multi_ajax_function(data);
}
return promises;
}
var exe_counter = 0;
// use $.when to call all the promises and once they're
// completed set exe_counter to 0, or whatever you need to do
$.when.apply(null, getPromises()).then(function () {
exe_counter = 0;
});
Related
In my project, data is distributed across groups of table. For reading the data, I need to make Async call to each of these groups (1...groupCount).
I need to call another function after all the data present in each of these groups is successfully read. What is the best way to do so?
function getData() {
for(var gc = 1; gc < groupCount; gc++)
readDataFromAsync(gc);
}
Assuming readDataFromAsync returns a jQuery deferred object
Use jQuery.when() and pass a callback to run when all is done.
function getData() {
var promises = [];
for (var gc = 1; gc < groupCount; gc++) {
promises.push(readDataFromAsync(gc));
}
$.when.apply(undefined, promises).done(function(/*...*/) {
// your code
});
}
First of all it is a bad practice to call AJAX several time, like inside of a loop.
If you can combine all the call and send all the request at a time, and take back all the response at a time then it will be best approach. For that you need to update server side code also.
But it is not possible always and depending on circumstances you need to call like this ways.
Here is some alternatives.
Use synchronous call insteted of async as follows
jQuery.ajax({
url: '.....',
success: function (result) {
//.....
},
async: false
});
But it will be slow since 1 by 1 call is there and not at all a good practice.
So you could count the ajaxResponse as a variable on your successful or unsuccessful response and call a final method when ajaxResponse reach it's cap as follows.
var ajaxResponse = 0;
function getData() {
ajaxResponse= 0;
for(var gc = 1; gc < groupCount; gc++)
readDataFromAsync(gc);
}
function readDataFromAsync(gc) {
$.ajax(...).success() {
//Your current code
ajaxResponse++;
if(ajaxResponse>=groupCount){
finalCall();
}
}
}
But there is problem also for the above approach. Handling ajaxResponse counter is difficult and there could be error occurred on ajax call.
You could also try setInterval and clearInterval instated of putting one if inside the success method but it will also costly.
Last one but best is approach provided by #Li Yin Kong as follows.
function getData() {
var promises = [];
for (var gc = 1; gc < groupCount; gc++) {
promises.push(readDataFromAsync(gc));
}
$.when.apply(undefined, promises).done(function(/*...*/) {
// your code
});
}
I have a an array called "products" that varies on each page load. I then need to call a function "addProduct()" for as many times as "products" is long, and use an altered value of each index inside that function. The function is long a complex and uses asynchronous calls (like .get) How can I stop the for loop from going to the next iteration until addProduct() is finished executing?
function addProduct(productVariable){
// (...do some long and asynchronous things with productVariable...)
}
//products array can vary in length on each page load
products = ["prod01","prod02","prod03","prod04","prod05",...];
for (var i = 0; i < products.length; i++) {
var productAlter = product[i];
//(...do some things with productAlter, but wait
// until the previous loop's addProduct() function
// has completed successfully)
addProduct(productAlter);
}
I keep reading about callbacks and promises, but no matter when I put them, the function seems to fire asynchronously. Any help is appreciated!
Will make use of success callback for Ajax to call addNextProdut and if the index reach its max then it will stop.
function addProduct(productVariable){
$.ajax({
url: your_action_server_url,
context: document.body,
success: function(){
addNextProduct()
}
})
}
function addNextProduct(){
index++;
if(index < products.length)
addProduct(products[index])
}
products = ["prod01","prod02","prod03","prod04","prod05",...];
index = 0;
addProduct(products[index])
I need to break cycle if proccess = true, but it's undefined.
var mapFound;
var locations = {$addressTest};
for (var i = 0; i < locations.length; ++i) {
getCoordinates(
locations[i],
function(proccess) {
}
)
if(proccess) { break; }
}
The problem seems to be basically that getCoordinates() makes an asynchronous call.
By the time the loop is over you haven't received even the first response, based on your question text, so you need to use another solution.
I mean by this that you won't be able to break the cycle, because by the time the cycle is over you still don't know if process is true.
Depending on your implementation you might want to take a look at promises. Although it might be easier to wrap the whole thing in a function that executes a callback:
function getCoords(locations, name, callback){
for (var i = 0; i < locations.length; i++) {
getCoordinates( locations[i], name,
function(proccess) {
if(process){
console.log("Map found in "+locations[i]);
callback.call();
}
}
);
}
}
getCoords({$addressTest}, {$name}, function(){
// Place here whatever you want to do once the map is found.
// you can get the map location by passing it as an argument for the callback.
});
I have a function "add_floor(xxx)" in a loop (see bellow) that take some time to complete, so i would like to know how to wait for the return of this function before moving to the next step which is in my case "add dawfeature points". I understand that I could use a callback method but then I would need to restart the complete loop that goes over the json elements in the calledback function. Not really sexy, so is there a way to avoid this ?
function add_maps_from_json(json) {
for (var i = 0; i < json.maps.length; i++) {
// add the maps to the combox box and display last one
add_floor(json.maps[i].mapName);
// add the dawfeature points to the map
for (var j = 0; i < json.maps[i].APs.length; j++) {
var idx = find_map_index();
console.log(idx);
var map = mapObjectArray[idx];
etc...
etc...
}
}
}
You can make the function return a value to a variable. That way the program will pause until the function as run. Like this:
var maps = add_maps_from_json(json);
Or you can use plugin.js and do module calls.
http://requirejs.org/docs/plugins.html
as you have said you have to add a callback parameter to add_floor and for managing your loop you can do async loop, like this:
//change the add_floor function
function add_floor(mapName, callback){
//your code
//you probably have some kind of ajax call or setTimeout
//then call your callback after your ajax response or timer callback
//....
callback();
//....
}
function add_maps_from_json(json) {
doLoop(json, 0)
}
function doLoop(json, i) {
if(i < json.maps.length) return;
add_floor(json.maps[i].mapName, function () {
// add the dawfeature points to the map
for (var j = 0; i < json.maps[i].APs.length; j++) {
var idx = find_map_index();
console.log(idx);
var map = mapObjectArray[idx];
//etc...
//etc...
}
doLoop(json, i + 1);
});
}
If add_floor doesn't do an ajax call, then your code will work fine as it is now.
If add_floor DOES do an ajax call, then you can put the inner for loop inside a separate function that you then use as the callback for the ajax call in add_floor.
Is that possible to set delay between the javascript for loop NOT using only settimeout but based on when an specific ajax call is done?
something like:
for (var i = 0 ; i < list.length ; i++)
{
$when('index.jsp').done(function(a1){
alert(i);
});
}
Say ajax request is sent and the first alert comes up, then the second iteration and alert is performed when the first ajax call is done.
I think the following should work:
(function() {
var i = 0, end = list.length;
function iterate() {
$.ajax('index.jsp').done(function() {
alert(i);
i++;
if (i < end) {
iterate();
}
});
}
iterate();
})();
An easy way to accomplish what you're after would be to use a callback in the Ajax function to recursively call itself. Otherwise I'm not sure of a way to do it in a for loop because Ajax calls are asynchronous.