for循环中的setTimeout不会打印连续值 [英] setTimeout in for-loop does not print consecutive values

查看:134
本文介绍了for循环中的setTimeout不会打印连续值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个脚本:

for (var i = 1; i <= 2; i++) {
    setTimeout(function() { alert(i) }, 100);
}

3 是提醒两次,而不是 1 然后 2

But 3 is alerted both times, instead of 1 then 2.

有没有办法传递 i ,而不将函数写为字符串?

Is there a way to pass i, without writing the function as a string?

推荐答案

你必须为每个超时功能安排一个i的独特副本。

You have to arrange for a distinct copy of "i" to be present for each of the timeout functions.

function doSetTimeout(i) {
  setTimeout(function() { alert(i); }, 100);
}

for (var i = 1; i <= 2; ++i)
  doSetTimeout(i);

如果你不做这样的事情(这个想法有其他变化),然后每个计时器处理函数将共享相同的变量i。当循环结束时,i的值是多少?这是3!通过使用中介函数,可以生成变量值的副本。由于超时处理程序是在该副本的上下文中创建的,因此它具有自己的私有i。

If you don't do something like this (and there are other variations on this same idea), then each of the timer handler functions will share the same variable "i". When the loop is finished, what's the value of "i"? It's 3! By using an intermediating function, a copy of the value of the variable is made. Since the timeout handler is created in the context of that copy, it has its own private "i" to use.

编辑—随着时间的推移,有一些评论表明,由于设置一些超时会导致处理程序同时全部触发,因此存在一些混淆。重要的是要了解设置计时器的过程—调用 setTimeout()—几乎没有时间。也就是说,告诉系统请在1000毫秒后调用此函数将几乎立即返回,因为在计时器队列中安装超时请求的过程非常快。

edit — there have been a couple of comments over time in which some confusion was evident over the fact that setting up a few timeouts causes the handlers to all fire at the same time. It's important to understand that the process of setting up the timer — the calls to setTimeout() — take almost no time at all. That is, telling the system, "Please call this function after 1000 milliseconds" will return almost immediately, as the process of installing the timeout request in the timer queue is very fast.

因此,如果发出超时请求的继承,就像OP中的代码和我的答案中的情况一样,并且每个时间延迟值相同,那么一旦时间已过去所有计时器处理程序将一个接一个地快速连续调用。

Thus, if a succession of timeout requests is made, as is the case in the code in the OP and in my answer, and the time delay value is the same for each one, then once that amount of time has elapsed all the timer handlers will be called one after another in rapid succession.

如果你需要的是每隔一段时间调用一次处理程序,你可以使用 setInterval(),其调用与 setTimeout()类似,但在重复延迟后会多次触发请求的金额,或者您可以建立超时并乘以迭代计数器的时间值。也就是说,修改我的示例代码:

If what you need is for the handlers to be called at intervals, you can either use setInterval(), which is called exactly like setTimeout() but which will fire more than once after repeated delays of the requested amount, or instead you can establish the timeouts and multiply the time value by your iteration counter. That is, to modify my example code:

function doScaledTimeout(i) {
  setTimeout(function() {
    alert(i);
  }, i * 5000);
}

100 毫秒超时,效果不会很明显,所以我将数字提高到5000.) i 的值乘以基本延迟值,所以调用循环中的5次将导致5秒,10秒,15秒,20秒和25秒的延迟。

(With a 100 millisecond timeout, the effect won't be very obvious, so I bumped the number up to 5000.) The value of i is multiplied by the base delay value, so calling that 5 times in a loop will result in delays of 5 seconds, 10 seconds, 15 seconds, 20 seconds, and 25 seconds.

更新

2018年,有一个更简单的选择。由于新功能在范围内声明变量比函数更窄,原始代码如果被修改则会起作用:

Here in 2018, there is a simpler alternative. With the new ability to declare variables in scopes more narrow than functions, the original code would work if so modified:

for (let i = 1; i <= 2; i++) {
    setTimeout(function() { alert(i) }, 100);
}

let 声明,与 var 不同,它本身会导致循环的每次迭代都有一个不同的 i

The let declaration, unlike var, will itself cause there to be a distinct i for each iteration of the loop.

这篇关于for循环中的setTimeout不会打印连续值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆