为什么javascript setTimeout()不能在循环中工作?
考虑以下代码:为什么javascript setTimeout()不能在循环中工作?,javascript,settimeout,Javascript,Settimeout,考虑以下代码: <!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()
<!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>
函数timedText()
{
var x=document.getElementById('txt');
var t=新数组();
t[1]=setTimeout(function(){x.value=“2秒”},2000);
t[2]=setTimeout(function(){x.value=“4秒”},4000);
t[3]=setTimeout(function(){x.value=“6秒”},6000);
}
函数timedTextArr()
{
var x=document.getElementById('txt');
var t=新数组();
对于(变量i=0;i<3;i++){
t[i]=setTimeout(function(){x.value=i*2+“seconds”},i*2000);
}
}
点击上面的按钮。输入字段将告诉您何时经过2秒、4秒和6秒
函数timedText()
起作用,但timedTextArr()
不起作用。这两个函数都将setTimeout()
中的返回值分配给数组元素。但是在for()
循环中,只有最后一个计时器工作。。。它工作了三次
这是一个错误吗?主要问题是,由于计时器函数的异步性质,循环在调用第一个超时之前运行,因此在第一个超时运行时,
i
被设置为2,在其他两个超时时保持不变
为了克服这一点,您应该考虑重构代码以使用一个间隔,这允许您与闭包同步:<代码> i <代码>的值:
var i=1;
var handle = setInterval( function() {
x.value = (i*2) + "seconds";
i++;
if (i>3) clearInterval(handle);
}, 2000 );
除此之外,循环的运行范围是从0到2,而不是1到3,就像在
timedText()
这不是一个bug,看看Javascript中的闭包是什么
基本上在函数的循环中
function(){x.value=i*2+" seconds"}
仅“看到”i变量的一个实例
循环结束后,i等于3,所有函数都是3
您需要在另一个匿名函数中包装调用以创建作用域,如下所示:
t[i] = setTimeout( (function(i){ return function(){x.value=i*2+" seconds"}})(i), i*2000 );
外部函数将创建一个新的作用域,在它内部,i将等于循环中i的值,并保持这样。您可以在那里尝试:获得相同结果的原因是
setTimeout
是异步的。这意味着在脚本的其余部分完成之前,它不会运行。然后,一旦它运行,i
的值被设置为等于3,因此所有函数运行时,它们看到的就是i=3。函数中的i
指的是循环中的i
,在任何超时触发时,它是6
。您需要添加一个闭包/范围:
for( var i = 0 ; i < 3 ; i++ ) {
(function(){ // create a closure (new scope)
var _i = i; // make a local copy of `i` from the outer scope
t[i] = setTimeout( function(){x.value=_i*2+" seconds"}, i*2000 );
})();
}
for(变量i=0;i<3;i++){
(函数(){//创建一个闭包(新范围)
var _i=i;//从外部作用域创建“i”的本地副本
t[i]=setTimeout(function(){x.value=_i*2+“seconds”},i*2000);
})();
}
没关系,因为我希望第一个setTimeout()为0秒,这样用户就可以立即看到一些有趣的东西。我将研究“javascript闭包”。谢谢。