Javascript事件循环说明



我不断看到对"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...]
}

但我一直看到这样的解释(见下面的例子):

事件循环:

  1. 检查(Javascript)调用堆栈是否为空。

  2. 检查回调队列[AKA EventQueue]是否为空。

  3. 如果调用堆栈为空并且回调队列不为空,则:

    a。取消最旧回调队列项目的队列。

    b。将回调函数推到调用堆栈上(没有提及调用该函数。)

  4. 保持循环。

这显然模糊地遵循了我上面假设的模型,但有两个关键和令人不安的区别:

A。为什么事件循环需要检查JS调用堆栈是否为空?当然,每次循环时,调用堆栈都会处于相同的状态(是否完全"空"无关紧要——不需要"检查")。上次调用的任何函数都将返回,从而恢复堆栈。所以这部分毫无意义。

B。为什么事件循环会"将回调推到JS堆栈上"?事件循环不应该只调用函数,从而创建一个合法的堆栈帧,以及从函数返回的方法吗,更不用说实际执行函数了吗?

因此,我希望能澄清这些解释以及为什么它们实际上是正确的,或者支持我对它们不正确的强烈怀疑。


这些事件循环解释的示例来源:

菲利普·罗伯茨:事件循环到底是什么?14:00https://youtu.be/8aGhZQkoFbQ?t=839

打字高性能(书)第83页。

什么是Javascript事件循环?http://altitudelabs.com/blog/what-is-the-javascript-event-loop/

了解Javascript函数执行-调用堆栈、事件循环、任务和;更多https://medium.com/@gaurv.pandvia/deunderstanding-javascript-功能-执行-任务-事件-停止-所有堆栈-更多部分-1-5683dea1f5ec

这是我对您的问题的回答:

JavaScript以单线程和同步的方式运行,因此事件回调函数将在全局执行上下文从执行堆栈弹出后执行。所有事件都将被添加到所谓的事件队列中。

全局执行上下文完成所有执行后,JS引擎将不断检查事件队列中是否存在任何事件。如果JS引擎看到有一个事件,那么它将为回调函数创建一个新的执行上下文,并将其推送到执行堆栈上。

在JS中,每次调用函数时,JS引擎都会创建一个执行上下文,该上下文创建一个私有范围,在该范围内声明的任何内容都不能从当前函数范围外直接访问,并推送执行上下文堆栈的顶部。函数执行完毕后,执行上下文将弹出

由于调用堆栈中执行的某些函数(事件处理程序、setTimeout、http请求)的异步特性,这些操作的消息(回调)可以随时添加到消息队列中。当主线程仍在调用堆栈中运行函数时,可能会发生这种情况,因此事件循环需要检查它是否为空。一旦为空,它将从消息队列中提取下一条消息,并将其放入调用堆栈。这个循环构成了事件循环的本质。

我做了一个视频演示,解释并演示了这个过程:https://www.youtube.com/watch?v=4xsvn6VUTwQ

最新更新