我正在学习异步编程,闭包等。我现在有一些难题。 这是代码:
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函数如何才能访问其值?
答案 0 :(得分:3)
1。i * 3000的值是多少?是:3000,6000,9000还是3000,3000,3000?
您的警报将显示4,4,4(循环完成后i
的值。)
您的setTimeout()
呼叫将获得时间值3000、6000、9000。setTimeout()
是无阻塞的。因此,设置了计时器,然后for
循环继续。
这里的问题是您的alert()
在for
循环完成后运行。因此,您将在i
循环结束时提醒for
的值。如果您更改为使用let
,如下所示:
for (let i = 1; i <= 3; i++){
setTimeout(function(){
alert(i + " second(s) elapsed");
}, i * 3000);
}
然后,i
将分别访问alert()
的每个循环值,而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引擎中养成习惯),则该范围仅适用于循环本身,实际上,每次循环调用都会有一个单独的变量实例,因此循环内的异步回调将可以访问属于其特定循环调用的i
。
有关垃圾回收的注意事项
使用let
时,循环完成后,变量将超出范围,但直到不再能访问循环内的所有代码后,该变量才有资格进行垃圾回收。因此,只要其中一个计时器仍处于活动状态,从循环内部访问i
的范围内值的代码仍将处于活动状态,因此,直到计时器(访问它。
重要的是要认识到,垃圾回收不仅受作用域控制。仅当没有可访问的代码访问该变量时,该变量才有资格进行垃圾回收。因此,包含函数或块(取决于声明变量的i
或var
)可能已经完成很长时间了,但是如果函数或块中还有异步操作仍可以调用( (例如您的计时器回调)仍具有对该变量的引用,则它的引用计数仍为正,并且无法进行垃圾回收。
请注意,这与考虑像C / C ++这样的典型堆栈框架世界中变量的生存期完全不同。尽管JS引擎内部的实现可能比这更复杂,但我的简单模型是我认为堆栈框架本身(使用函数或块声明的所有变量)本身都是垃圾收集的,因此可以一直存在直到函数内没有任何代码(包括异步回调)仍然可以到达它。
关于非阻塞let
对于循环中如何调用多个setTimeout()
调用,您似乎感到困惑,但是循环一直在运行。这是因为setTimeout()
是非阻塞的。这意味着它将在JS引擎内部注册一个计时器,然后立即返回以允许您的setTimeout()
循环继续运行。然后,一段时间之后,for
循环完成并且所有三个计时器都已设置之后,JS引擎将调用与每个计时器关联的回调,然后运行该回调中的代码。
请考虑非阻塞性概念,例如在日历中设置提醒。您设置提醒(比如说下午4点约会),然后继续进行其他业务。然后,在您下午4点约会之前,日历会通知您即将到来的约会。提醒的设置是非阻塞的。提醒已注册,然后您可以继续处理其他事务。 for
的工作方式与Javascript中几乎所有异步操作的工作方式相同。它们是非阻塞的。他们开始,计划或启动,然后立即返回,允许您的Javascript继续执行其想做的任何事情。然后,在一段时间之后,当异步操作完成并且JS解释器没有执行其他操作时,将调用与异步操作完成相关的回调,并且该回调中的JS将运行。
有关Java事件驱动性质的更多信息,请参见以下内容:
How does JavaScript handle AJAX responses in the background?和该帖子中引用的9个链接。
Why does a while loop block the event loop?