我一直看到" Javascript事件循环的解释" (即:浏览器JS运行时事件循环)对我来说似乎不合理,我希望有人可以提供一些权威的澄清。
我的基本假设是JS事件循环就像我们几十年来一直在UI框架中使用的事件循环一样,如:
// [... some initialization ...]
// The Event Loop
while (true) {
if (! EventQueue.isEmpty()) {
event = EventQueue.pop_oldest_item();
event.callback(event [or some other kind of args]);
}
// [... defer to other non-JS tasks...]
}
但我一直在看这样的解释(见下面的例子):
事件循环:
检查(Javascript)调用堆栈是否为空。
检查回调队列[AKA EventQueue]是否为空。
如果调用堆栈为空并且回调队列不为空,则:
一个。将最旧的回调队列项出列。
湾将该回调函数推送到调用堆栈(并且没有提到调用该函数。)
继续循环。
这显然模糊地遵循我上面假设的模型,但有两个关键和令人不安的差异:
一个。为什么事件循环需要检查JS调用堆栈是否为空?当然,每次循环时,调用堆栈都将处于相同的状态(无论是完全"空的"是否接近点 - 它不需要"检查&# 34)。无论上次调用什么函数都会返回,恢复堆栈。所以那部分毫无意义。
B中。为什么事件循环"将回调推送到JS堆栈"?不应该事件循环只调用函数,从而创建一个合法的堆栈帧,以及从函数返回的方法,更不用说实际执行函数了吗?
所以我希望得到澄清,解释这些解释以及为什么它们实际上是正确的,或者支持我强烈怀疑它们是不正确的。
这些事件循环说明的示例来源:
Philip Roberts:事情循环到底是什么? 14:00 https://youtu.be/8aGhZQkoFbQ?t=839
打字稿高性能(书)第83页。
什么是Javascript事件循环? http://altitudelabs.com/blog/what-is-the-javascript-event-loop/
理解Javascript函数执行 - 调用堆栈,事件循环,任务&更多 https://medium.com/@gaurav.pandvia/understanding-javascript-function-executions-tasks-event-loop-call-stack-more-part-1-5683dea1f5ec
答案 0 :(得分:1)
这是我对你问题的回答:
JavaScript以单线程和同步方式运行,因此事件回调函数将在全局执行上下文弹出执行堆栈后执行。所有活动都将添加到名为事件队列的内容中。
在全局执行上下文完成所有执行后,JS引擎将继续检查事件队列中是否存在任何事件。如果JS引擎看到有一个事件,那么它将为回调函数创建一个新的执行上下文并将其推送到执行堆栈。
在JS中,每次调用一个函数时,JS引擎都会创建一个执行上下文,这会创建一个私有作用域,其中在函数内部声明的任何内容都不能从当前函数外部直接访问范围,并推送执行上下文堆栈的顶部。函数完成执行后,将弹出执行上下文。
答案 1 :(得分:0)
由于在调用堆栈中执行的某些功能(事件处理程序,setTimeout,http请求)的异步性质,可以随时将这些操作中的消息(回调)添加到消息队列中。当主线程仍在调用堆栈中运行函数时,可能会发生这种情况,因此事件循环需要检查其是否为空。一旦为空,它将从消息队列中提取下一条消息并将其放入调用堆栈中。这个周期构成了事件循环的本质。
我做了一个视频演示,解释并演示了此过程: https://www.youtube.com/watch?v=4xsvn6VUTwQ