在 for 循环中使用 setTimeout 不会打印连续的值。
在 for 循环中使用 setTimeout 不会打印连续的值。
这个问题已经在这里有了答案:
我有这个脚本:
for (var i = 1; i <= 2; i++) { setTimeout(function() { alert(i) }, 100); }
但是,两次都弹出 3
,而不是先弹出 1
,然后弹出 2
。
有没有一种方法可以传递 i
,而无需将函数作为字符串编写?
admin 更改状态以发布 2023年5月21日
你必须为每个超时函数准备一个独立的“i”副本。
function doSetTimeout(i) { setTimeout(function() { alert(i); }, 100); } for (var i = 1; i <= 2; ++i) doSetTimeout(i);
如果你不这样做(也有其他变体),那么每一个计时器处理函数将共享同一个变量“i”。当循环结束时,“i”的值是什么?是3!通过使用一个中间函数,变量的值的副本被创建。由于超时处理程序是在该副本的上下文中创建的,它具有自己的私有“i”可供使用。
编辑:
随着时间的推移,有几个评论表明存在某些混淆,即设置几个超时会导致处理程序同时触发。重要的是要了解,设置计时器的过程-调用
setTimeout()
几乎不需要时间。也就是说,告诉系统:“在1000毫秒后调用此函数”将立即返回,因为在计时器队列中安装超时请求的过程非常快。因此,如果连续发出超时请求,例如在OP中的代码和我的答案中的情况,并且时间延迟值对于每个请求都是相同的,那么一旦经过了这段时间,所有计时器处理程序将依次快速地调用。
如果你需要处理程序按间隔调用,你可以使用
setInterval()
,它与setTimeout()
的调用方式完全相同,但是会在重复延迟请求的情况下多次触发,或者你可以建立超时,并将时间值乘以迭代计数器。也就是说,修改我的示例代码:function doScaledTimeout(i) { setTimeout(function() { alert(I); }, i * 5000); }
(使用100毫秒的超时时间,效果不会非常明显,因此我将数字增加到了5000。)变量i的值将乘以基本延迟值,因此在循环中调用5次将导致5秒、10秒、15秒、20秒和25秒的延迟。
更新
在2018年,有一个更简单的替代方案。由于能够在比函数更狭窄的作用域中声明变量,因此可以修改原始代码,使其正常工作:
for (let i = 1; i <= 2; i++) { setTimeout(function() { alert(i) }, 100); }
let
声明,与var
不同,将导致循环的每次迭代中都有一个独立的i。