0

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?

0

5 Answers 5

6

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.

Sign up to request clarification or add additional context in comments.

Comments

4

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.

1 Comment

@minitech, thanks, but FYI, it doesn't make any difference. AFAIK, it's a matter of preference.
1

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);

Comments

1

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.

2 Comments

That actually also won't work, as JavaScript has no scope other than function scope. nextFunction will be redefined. jsfiddle.net/N9LBU Also, you didn't fix the * i problem. -1
Well, you can still correct it in your post - votes are flexible.
0

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);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.