Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/426.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么javascript setTimeout()不能在循环中工作?_Javascript_Settimeout - Fatal编程技术网

为什么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闭包”。谢谢。