This loop is in a function and it counts down from 10, however if I alert the parameter passed using i in the setV function it actually counts up!
for (var i=10;i>0;i--){
setTimeout('setV('+i+',"Out")',100);
}
function setV(c,t){
alert(c);
}
All the setV are programmed to execute at the same time (100ms after the instaneous loop execution), the order isn't determined (see the spec).
You probably wanted
for (var i=10;i>0;i--){
setTimeout('setV('+i+',"Out")',100*(11-i));
}
If you are describing the behavior with:
setTimeout('setV('+i+',"Out")',i*100);
the reason it counts up is because a callback set for 1s will execute earlier than one set for 2s, which will execute earlier than one set for 3s...
When all of the timeouts are set to run at the same time, there is no promise what order they will run this.
This is a much better way to write that loop:
function initThis() {
var idx = 0;
function doOneIteration() {
window.alert(idx);
idx++;
if (idx <= 10) {
window.setTimeout(doOneIteration);
}
}
doOneIteration(); // Start loop
}
initThis(); // This makes it all happen
Related
In the following code, I tried to keep timeout but it doesn't work. I am sending array and expecting array index with 3 sec delay.
function displayIndex(arr){ // array as input
for(var i=0;i<arr.length; i++){
SetTimeout(function(){
console.log(i); // always returns 4
},3000);
}
}
displayIndex([10,20,30,40])
update:
var arr = [10,20,30,40];
function displayIndex(arr){ // array as input
for(var i=0;i<arr.length; i++){
setTimeout(function () {
var currentI = i; //Store the current value of `i` in this closure
console.log(currentI);
}, 3000);
}
}
displayIndex(arr); // still prints all 4.
Also, tried
arr.forEach(function(curVal, index){
setTimeout(function(){
console.log(index);
},3000);
}); // prints 0 1 2 3 but I do not see 3 secs gap between each display, rather one 3 sec delay before everything got displayed.
Use this:
function displayIndex(arr){ // array as input
var i=0;
var current;
run=setInterval(function(){ // set function inside a variable to stop it later
if (i<arr.length) {
current=arr[i]; // Asign i as vector of arr and put in a variable 'current'
console.log(current);
i=i+1; // i increasing
} else {
clearInterval(run); // This function stops the setInterval when i>=arr.lentgh
}
},3000);
}
displayIndex([10,20,30,40]);
1st: If you use setTimeout or setInterval function inside a for that's a problem 'couse all this are loops ways (the first two are loops with time intervals). Aaand setTimeout just run code inside once.
Note: setInterval need a function to stop it clearInterval, so that's why i put an if inside.
2nd: You are not setting currentI or i like a vector of arr operator. When you run an array the format is: arr[currentI], for example.
Doubts?
SetTimeout should be setTimeout. It's case-sensitive.
You're setting 4 timeouts all at once. Since you're incrementing the value of i every loop, it's going to be 4 at the end of the loop.
I'm not really sure what you're trying to do, but perhaps you wanted this?
setTimeout(function () {
var currentI = i; //Store the current value of `i` in this closure
console.log(currentI);
}, 3000);
The reason why it's behaving unexpectedly:
Case 1: In the first snippet, setTimeout() is adding the functions to the Event Queue to be executed after main thread has no more code left to execute. The i variable was passed as reference and, so the last modified value gets printed on each call since, it was passed by reference.
Case 2: In this case, since you are passing 4 explicit references, the values are different but, the execution order will same ( I.e., synchronous and instantaneous).
Reason: setTimeout() function always pushes the function passed to the queue to be executed with the delay acting as a minimum guarantee that it will run with the delayed interval. However, if there is code in the queue before the function or, any other code in the main thread, the delay will be longer.
Workaround: If you do not to implement blocking behaviour in code, I would suggest using an analogue of process.hrtime() for browser ( there should be a timing method on the window object and, write a while loop that explicitly loops until a second has elapsed.
Suggestion: I am somewhat confused as to why you need such blocking in code?
Running the code, the browser will display RangeError.
function hide() {
h -= step;
pp.style.height = h + "px";
setTimeout(hide(), 1);
}
The problem is this line:
setTimeout(hide(),1);
Rather than telling JavaScript to call hide() again in 1 millisecond you actually call it immediately and only pass it's return value to setTimeout(). This causes an infinite recursion, which in the end causes the stack overflow/error you're getting.
To fix this, you'll have to use either syntax from your question's title:
Pass the function name only rather than calling it (better here).
Pass a lambda function.
Or pass the call inside a string that will be evaluated (IMO should be avoided or replaced with a lambda expression).
However, in your specific scenario I'd suggest using set Timeout(), considering your code is reasonably simple to always finish in time:
// Start the while thing
var handle = setInterval(hide, 1);
// Actual function
function hide()
{
// Do stuff
// End condition
if (done)
clearInterval(handle);
}
This code doesn't terminate, so it creates infinite number of stacks which causes stack overflow.
Consider adding some termination logic, like:
if (h < 0) { return }
This terminates the execution of hide() function when h is less then 0.
I'm assuming h and step are some global vars.
Also you're calling hide immediately and passing the value to setTimeout.
Correct way to recursively call function with timeout will be to pass function as value to setTimeout function:
setTimeout(hide, 1)
which is equivalent to:
setTimeout(function() { hide() }, 1)
I am trying to create a FOR loop that removes an element every 1000ms instead of rushing instantaneously through the array and perform the operations.
I am doing this for reasons of performance since going normally through the loop freezes my UI.
function removeFunction (i,selected) {
selected[i].remove();
}
function startLoop() {
var selected = paper.project.selectedItems;
for (var i = 0; i < selected.length; i++) {
if (selected[i].name === "boundingBoxRect") continue;
setTimeout(removeFunction(i,selected),1000)
}
}
It seems that the selected[i].remove() method is getting called without any delay. Why is that? Since I have set a Timeout of 1000ms shouldn't the items get removed with 1000ms interval between each?
Note
In the code above, I am skipping an item called boundingBoxRect since I don't want to remove that. Just stating this so there is no confusion
Simply turn it into a recursive function:
function removeFunction (i, selected) {
// If i is equal to the array length, prevent further execution
if (i === selected.length)
return;
// Remove ith child of selected array
selected[i].remove();
// Trigger same function after 1 second, incrementing i
setTimeout(function() {
removeFunction(++i,selected)
}, 1000);
}
// Trigger the function to begin with, passing in 0 as i
removeFunction(0, paper.project.selectedItems);
Here's a JSFiddle demo (using console.log instead of selected[i].remove(), as you haven't provided a definition for that function);
It seems that the selected[i].remove() method is getting called without any delay. Why is that?
Because that's what you're telling it to do. setTimeout(removeFunction(i,selected),1000) calls removeFunction immediately and passes its return value into setTimeout, exactly the way foo(bar()) calls bar and passes its return value into foo.
You can get the effect you want by using a builder function:
setTimeout(buildRemover(i,selected),1000);
...where buildRemover is:
function buildRemover(index, array) {
return function() {
removeFunction(index, array);
};
}
Note how buildRemover creates a function that closes over the index and array variables. Then it returns a reference to that function, which is what gets scheduled via setTimeout. When the timeout occurs, that generated function is called, and it calls removeFunction with the appropriate values.
You can also do something similar using ES5's Function#bind:
setTimeout(removeFunction.bind(null, i, selected),1000);
Function#bind returns a new function that, when called, will call the original (removeFunction above) use the given this value (null in our example) and arguments.
I'm working on this code puzzle from here
Here's what I have so far:
for (var i = 0; i < 1000; i += 100) {
waitFor(i, function then() {
console.log(i)
})
}
// this will run a callback function after waiting milliseconds
function waitFor(milliseconds, callback) {
setTimeout(callback.apply(), milliseconds)
}
This logs out 0 to 900, but it does it all at once, and then waits 900 milliseconds at the end (instead of waiting i milliseconds in between each console.log).
Can anyone help me understand this?
You have two different issues going on in your code:
Closures are causing the value 1000 to printed always instead of 100, 200 ... etc.
The timeouts you are using are too short, so the functions are executing rapidly in succession.
The first problem is hard to explain in a single answer but I will try to give you some insights, since the function that is printing the value of the variables to the console is defined inside the for loop, that function will always keep the value of i that was there when the loop ended, and in your situation this is 1000.
To solve this problem, you need something similar to what #thg435 referred to in his comment, something like this:
// this will run a callback function after waiting milliseconds
function waitFor(milliseconds, callback) {
setTimeout(callback, milliseconds);
}
function createFunction(i) {
return function() { console.log(i); };
}
for (var i = 0; i < 1000; i += 100) {
waitFor(i, createFunction(i));
}
The second problem is that the values for the timeout are actually the values that i take as it is looping which are 100, 200 ... etc which are all very small values less than a second, so when the for loop finishes, those functions will all be ready to executed so they will get executed immediately one after the other.
To solve this issue you need to use a bigger time gap by multiplying i by 10 for example, like the following:
waitFor(i*10, createFunction(i));
^^^^
First timer call will be happenned when loop will be finished. In this context i = 1000 due to JS uses reference not a value. To fix this situation you have to use closures.
I'm holding code lines in an array, and trying to run them cell by cell with setTimeout().
This executes the code well:
for (i=0; i<restorePoints.length; i++){
eval(restorePoints[i]);
}
but I want to have a short delay between every iteration: i want to use setTimeout() instead of eval(). for some reason none of those work:
for (i=0; i<restorePoints.length; i++){
setTimeout(restorePoints[i],1000);
}
or
for (i=0; i<restorePoints.length; i++){
setTimeout(eval(restorePoints[i]),1000);
}
how do I do it?
thanks
The loop is fast. It will create all timeouts in a row, so all timeouts will fire at the same time. You can either make the time depended on the loop variable, i.e. increasing the time in every iteration, or, what I would do, use only one timeout and a recursive call:
(function() {
var data = restorePoints;
var run = function(i) {
setTimeout(function() {
var entry = data[i];
if(entry) {
eval(entry);
run(i+1);
}
}, 1000);
};
run(0);
}());
Note that there is a difference between eval(string) and setTimeout(string, ...) apart from the delay:
eval will evaluate the parameter in the current scope while setTimeout (and setInterval) will evaluate it in the global scope.
This might be relevant to you.
If you're going to do it either of those ways, you'll need to wrap the function call in an anonymous function:
for (i=0; i<restorePoints.length; i++){
setTimeout(function(){eval(restorePoints[i]}),1000);
}
Otherwise you're not setting the eval to fire in a timeout, you're setting the result of the executing Javascript code (whatever that might be in this case) to be the thing setTimeout is opperating against.