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.
Related
I saw a lot of questions about how to put delay or sleep in javascript. I tried everything i just could not have the code work, like i wanted to.
So i get like 500 friend requests on facebook, kinda annoying accepting one them one by one. So i found the script which does accept all my friend requests at once. I tried the set time out and sleep codes, which actually do the work but i want to put the delay between each actions. With Set timeout, it just delays the whole script. So i wanna do like this:
Confirm
1sec delay
Confirm
1sec delay
confirm
1sec deleay...
Here is my original script:
var field = document.getElementsByName("actions[accept]");
for (i = 0; i < field.length; i++)
field[i].click() ;
Here is another solution for this, we need to call immediate function with "i" param to get it correct into setTimeout:
var field = document.getElementsByName("actions[accept]");
for (var i = 0; i < field.length; i++) {
(function(i){
setTimeout(function() {
field[i].click();
}, i * 1000);
})(i);
}
But I suggest to use recursion answer above as better solution for this, because good practise not to use functions in loop. Here is reference :
https://jslinterrors.com/dont-make-functions-within-a-loop
The correct solution to your problem would be the following:
var field = document.getElementsByName("actions[accept]");
var index = 0;
function acceptFriends(){
if(index<field.length){
field[index].click();
index++;
setTimeout(acceptFriends,1000);
}
}
acceptFriends();
var field = document.getElementsByName("actions[accept]");
for (i = 0; i < field.length; i++){
setTimeout(function(){field[i].click()},(i*1000))
}
How can we make the asynchronous function stop and wait for the response?
I got some solution about getting the value from asynchronous functions from How do I return the response from an asynchronous call? But, I still have more questions about how can we get a value from asynchronous function if we have to pass in some values to the function.
Here, I have 3 functions. First, the asynchronous function.
function getVal(param,callbackFunc)
{
a = function()
{
if(a.state==finished)
callbackFunc(a.response);
};
}
This one is the call back function
handler(result)
{
return result;
}
And, This is where I call the asynchronous function, and also where I got the problem
function core()
{
for(var i = 0 ; i < 10 ; i ++)
{
getVal(g[i],handler);
}
}
As you can see, the parameter I sent to the getVal function is an array. So, the question is how can we make the getVal function execute the parameters synchronously.
This always give me the result of the last member of array (It seems like the function skips all values from g[0] to g[9].it always returns the value of getVal(g[10],handler)) .
Please help
Thank you.
Your problem is not directly related to Ajax, it occurs whenever the execution of a code block is delayed. The following code snippets reproduce this situation using a timer. The last code snippet is a possible solution to your problem. By the way, if you still feel confused about Ajax, here is an attempt to make it easy to understand: https://stackoverflow.com/a/32163917/1636522.
No delay: i is printed immediately.
print('loop start');
for (var i = 0; i < 3; i++) {
print(i);
}
print('loop end');
function print (html) {
document.body.innerHTML += html + '<br />';
}
1 second delay: The print action is executed 1 second later, but the "for" loop keeps going, hence, i reaches 3 before being printed.
print('loop start');
for (var i = 0; i < 3; i++) {
setTimeout(function () {
print(i);
}, 1000);
}
print('loop end');
function print (html) {
document.body.innerHTML += html + '<br />';
}
1 second delay + persistence: i is copied to a new variable. This variable is local to the self-invoking function and still alive when the print function is called.
print('loop start');
for (var i = 0; i < 3; i++) {
(function (copy) {
setTimeout(function () {
print(copy);
}, 1000);
})(i);
}
print('loop end');
function print (html) {
document.body.innerHTML += html + '<br />';
}
One way to do that is by making ajax request synchorous.
var xhr =new XMLHttpRequest();
xhr.open("GET","url", false);
False here will make sure rest of the code isnt ran until havent gotten response.
Otherwise what i do is make all async requests then upon every response subtract 1 from array.length and check if it's zero. If it is then it means we have gotten all of the responses so then call the callback.
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;
});
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.
I have something like this:
for (var i=0;i<result.qry.ROWCOUNT;i++) {
myAsync(i);
}
How do I know when all my Async functions have finished executing?
At the risk of someone replying with "Needs more jQuery!", can I use the jQuery promise object? Or deferred or something like that?
Keep track of how many asynchronous calls are outstanding. When each finishes, decrement your counter. When you get to 0, you are in the last callback.
var asyncsLeft = 0;
for (var i=0;i<10;++i){
asyncsLeft++;
doSomethingAsyncWithCallback(function(){
// This should be called when each asynchronous item is complete
if (--asyncsLeft==0){
// This is the last one!
}
});
}
Due to the single-threaded nature of JavaScript there is no potential race condition where you might get your callback invoked before all of the asynchronous calls have been queued up. It is safe to put the asyncsLeft++ call after the doSomethingAsynchronous, if you like.
This is how I would do it:
//Do stuff up here to get records
var rowCount = result.qry.ROWCOUNT, //Save the row count
asyncCount = 0, //The count of complete async calls
asyncCallback = function() {
//To be called whenever an async operation finishes
asyncCount++; //Increment the row counter
if (asyncCount >= rowCount) {
//Do stuff when they're all finished
}
};
for (var i=0;i<rowCount;i++) {
myAsync(i, asyncCallback);
}
function myAsync(index, completeCallback) {
//Do async stuff with index
//Call completeCallback when async stuff has finished or pass it
// into the async function to be called
}
In jQuery, there is the $.ajaxStop function that runs after the last Ajax has ran.
If you are using jQuery, you can also use the ajaxSend and ajaxComplete methods to keep your counter code separate from your dispatch code.
var ajaxPending = 0;
function ajax_changed(indicator, pending) {
if (pending)
$(indicator).show();
else
$(indicator).hide();
}
$('#loading-indicator').ajaxSend(function() {
ajax_changed(this, ++ajaxPending);
});
$('#loading-indicator').ajaxComplete(function() {
ajax_changed(this, --ajaxPending);
});
Use a callback function:
for (var i=0;i<result.qry.ROWCOUNT;i++) {
myAsync(i, myCallback);
}
function myCallback(i){
//set result.qry.ROWCOUNT to a var somewhere above if it's not available in this scope
if(i == (result.qry.ROWCOUNT - 1)){
//now you know you're actually done with all requests
}
}
function myAsync(i,callback){
///do work
callback(i);
}