why does javascript setTimeout() not work in a loop?

javascript, settimeout

Solution

This is not a bug, have a look at what closures are in Javascript.

Basically in your for loop the function

function(){x.value=i*2+" seconds"}

only "sees" one instance of the i variable.

So once the loop is over, i is equal to 3, so it is 3 for all functions.

You need to wrap the call in another anonymous function to create a scope, like this:

t[i] = setTimeout( (function(i){ return function(){x.value=i*2+" seconds"}})(i), i*2000 );

The outer function will create a new scope, and inside it i will be equal to the value of i in the loop and stay like this. You can try it out there: http://jsfiddle.net/6b68E/

Problem

Consider the following code: ``` <!DOCTYPE html> <html> <head> <script> function timedText() { var x=document.getElementById('txt'); var t = new Array(); t[1] = setTimeout( function(){x.value="2 seconds"}, 2000 ); t[2] = setTimeout( function(){x.value="4 seconds"}, 4000 ); t[3] = setTimeout( function(){x.value="6 seconds"}, 6000 ); } function timedTextArr() { var x=document.getElementById('txt'); var t = new Array(); for( var i = 0 ; i < 3 ; i++ ) { t[i] = setTimeout( function(){x.value=i*2+" seconds"}, i*2000 ); } } </script> </head> <body> <form> <input type="text" id="txt" /> <input type="button" value="Display timed text!" onclick="timedText()" /> <input type="button" value="Display timed text Arr!" onclick="timedTextArr()" /> </form> <p>Click on the button above. The input field will tell you when two, four, and six seconds have passed.</p> </body> </html> ``` Function `timedText()` works, but `timedTextArr()` doesn't. Both functions assign return values from `setTimeout()` to array elements. But in the `for()` loop, only the last timer works... and it works three times. Is this a bug?

Original source

Related problems