I want to do something like this:
for(var i=0;i<aList.length;i++)
{
aList[i].doSomething();
sleep(500);
}
Of course, there's no sleep function in javascript so I tried the following:
for(var i=0;i<aList.length;i++)
{
setTimeout(function(){
aList[i].doSomething();
},500);
}
However, now it says aList[i] is not defined. Since the anonymous function is a closure, it is actually reading aList[i] from the scope of the outside function, and thus by the time the function in setTimeout is being run, i
has already changed.
What is a way to accomplish this?
A quick fix to emulate JavaScript 1.7's let
is to wrap it in a function:
for(var i=0; i < aList.length; i++) {
(function(i) {
setTimeout(function() {
aList[i].doSomething();
}, 500 * i); // <-- You need to multiply by i here.
})(i);
}
I also added a fix to a little bug in which the script will pause 500 seconds, then execute all of them. setTimeout
is non-blocking.
This is what you probably want:
for(var i=0;i<aList.length;i++)
{
(function(i){
// Retain `i` in this scope, for use later (after timeout)
setTimeout(function(){
aList[i].doSomething();
}, 500 * i);
})(i);
}
You want the 500 * i
so that each step is 500ms later than the last, otherwise everything will happen at once after 500ms. Notice the extra wrapping function -- this essentially traps/retains the value of i
.
One of the variants:
var array = [/*elements*/],
i,
length = array.length,
loop = setInterval(function() {
array[i].doSomething();
i += 1;
if (i === length) {
clearInterval(loop);
}
}, 500);
Just define the function before the timeout
for(var i=0; nextFunction = aList[i];i++) {
var waitAndDoSomething = function(func) {
return function() { func.doSomething(); }
};
setTimeout(waitAndDoSomething(nextFunction),500*i);
}
Another Possible Answer
At minitect's suggestion, I started to think about other possible solutions. A solution that I feel comes out clean is to use bind
String.prototype.doSomething = function() { alert(this); } // Just for testing
var aList = ['one', 'two', 'three']; // Just for testing
for(var i=0;obj = aList[i];i++) {
setTimeout(obj.doSomething.bind(obj),500*i);
}
However, I am not sure how well this would work in the context of Razor Storm's question because I don't know what aList[i] would represent.
Does this answer the question
I also wonder if this is the intended behavior. It will not actually sleep after the execution but rather sets timing. This can be deceiving, but if we really want to execute a function and then sleep for a half a second before the next one our timing is off here. Instead I would use recursion:
String.prototype.doSomething = function() { alert(this); }
var aList = ['one', 'two', 'three'];
var doNextSomething = function(index) {
if (!index) { index = 0 }
if (nextObject = aList[index]) {
nextObject.doSomething();
setTimeout(doNextSomething, 500, index + 1);
}
};
doNextSomething();
Now, it will wait for 500 milliseconds after the function is executed (evident in a long running task).
I think that the answers posted were more what Razor Storm had it mind though.
before the for loop do something like:
var _aList = aList;
Within the loop you have to setTimeout and the delay 500 * i.
So the result will be:
var _aList = aList;
for(var i=0;i<aList.length;i++)
{
(function(obj, index) {
setTimeout(function(){
obj.doSomething();
},500 * index);
})(aList[i], i);
}