繁体   English   中英

在for循环中使用setTimeout

[英]setTimeout in a for loop

我正在学习异步编程,闭包等。我现在有一些难题。 这是代码:

  for (var i = 1; i <= 3; i++){
  setTimeout(function(){
    alert(i + " second(s) elapsed");
  }, i * 3000);
}

我知道在调用setTimeout函数时,for循环已经完成(值i=4 )。 我的问题:

1. i*3000的值是多少? 是:3000,6000,9000还是3000,3000,3000?

2.setTimeout函数在for循环中,如果在循环结束并关闭后调用它,它实际存储在哪里?

3. var i在for循环中声明。 因此,当for循环完成并关闭时,应将其从作用域中删除。 setTimeout函数如何才能访问其值?

1. i * 3000的值是多少? 是:3000,6000,9000还是3000,3000,3000?

您的警报将显示4,4,4(循环完成后i的值)。

您的setTimeout()调用将获得3000、6000、9000的时间值setTimeout()是非阻塞的。 因此,设置了计时器,然后for循环继续。

这里的问题是for循环完成后,您的alert()运行。 因此,您将在for循环结束时提醒i的值。 如果更改为使用let as:

for (let i = 1; i <= 3; i++){
  setTimeout(function(){
    alert(i + " second(s) elapsed");
  }, i * 3000);
}

然后,您的alert()将分别访问i每个循环值,并且alert()将显示1、2、3。

另外,请切换到使用console.log(i + " second(s) elapsed"); 因为alert()可能会使事情发生时间混乱(不是在这里,但是可以)。

2.setTimeout函数在for循环中,如果在循环结束并关闭后调用它,它实际存储在哪里?

不清楚“实际存储”是什么意思。 setTimeout()是内置在Javascript引擎核心中的系统功能。 活动计时器存储在JS引擎内部。

3.var i在for循环中声明。 因此,当for循环完成并关闭时,应将其从作用域中删除。 setTimeout函数如何才能访问其值?

var声明的变量的作用域为包含函数 ,而不仅限于循环,因此可以在包含函数中的任何位置使用。

如果使用let而不是var (通常在任何现代Javascript引擎中都应习惯使用var ),则该范围仅适用于循环本身,实际上,每个变量都有一个单独的变量实例循环的调用,因此循环内的异步回调将有权访问属于其特定循环调用的i

垃圾收集注意事项

使用let ,变量在循环完成后将不在范围内,但是直到不再能访问循环内的所有代码后,该变量才有资格进行垃圾回收。 因此,只要其中一个计时器仍处于活动状态,那么从循环内访问i的作用域内值的代码仍将处于活动状态,因此,直到访问它的计时器触发之前,每个i都不会被垃圾回收。

重要的是要认识到,垃圾回收不仅受范围控制。 仅当没有可访问的代码访问该变量时,该变量才有资格进行垃圾回收。 因此,包含函数或块(取决于varlet声明变量的位置)可能已经完成很长时间了,但是如果函数或块内部仍可以调用(例如您的计时器回调)异步操作,对该变量的引用,则其引用计数仍为正,并且无法进行垃圾回收。

请注意,这与思考变量在诸如C / C ++这样的典型堆栈框架世界中的生命周期完全不同。 尽管JS引擎内部的实现可能比这更复杂,但我的简单模型是我认为堆栈框架本身(使用函数或块声明的所有变量)本身都是垃圾收集的,因此可以一直存在直到函数内没有代码(包括异步回调)仍然可以到达它。

关于非阻塞setTimeout()注释

您似乎对如何在循环中调用多个setTimeout()感到困惑,但是循环一直在运行。 这是因为setTimeout()是非阻塞的。 这意味着它会在JS引擎内部注册一个计时器,然后立即返回以允许您的for循环继续运行。 然后,一段时间后,在完成for循环并设置了所有三个计时器之后,JS引擎将调用与每个计时器关联的回调,然后运行该回调中的代码。

将非阻塞概念想像为在日历中设置提醒。 您设置提醒(比如说下午4点约会),然后继续进行其他业务。 然后,在您下午4点约会之前,日历会通知您即将到来的约会。 提醒的设置是非阻塞的。 提醒已注册,然后您可以继续处理其他事务。 这与setTimeout()工作方式以及Javascript中几乎所有异步操作的方式相同。 它们是非阻塞的。 他们开始,计划或启动,然后立即返回,允许您的Javascript继续执行其想做的任何事情。 然后,在某个时间之后,当异步操作完成并且JS解释器没有执行其他操作时,将调用与异步操作完成相关的回调,并且该回调中的JS将运行。


有关Java事件驱动性质的更多信息,请参见以下内容:

JavaScript如何在后台处理AJAX响应? 以及该帖子中引用的9个链接。

为什么while循环会阻止事件循环?

setTimeout在Node.js中等待太长时间

等到flag = true

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM