JS调用堆栈是否始终至少有一个帧

Does the JS callstack always have at least one frame?

本文关键字:有一个 调用 堆栈 是否 JS      更新时间:2023-09-26

我最近看过一个关于JS事件循环的演示,坦率地说,这很棒,但是我现在有一个关于JS调用堆栈的挥之不去的问题。如果您将全局执行上下文视为 main((,那么 main(( 是否从未解析过?我在这里的推理是,如果是这样,那么JS程序将是完整的,并且不会发生回调。

--编辑

我在这里的主要兴趣是如何表示与回调队列相关的调用堆栈。如果说事件循环等到调用堆栈为空,然后再将新帧推送到堆栈上,则循环将等到程序完成,并且回调不会有任何影响。

我想这意味着事件循环会等到只剩下一帧(主执行上下文(,而不是没有帧。

如果您将全局执行上下文视为 main((

不。 main不是全局执行上下文,而是最初在该上下文中运行的代码。全局环境 - 通过闭包 - 在全局代码运行后仍保留未完成的回调,在您的程序完成之前,它不会被垃圾回收。

main(( 从未解析过吗?

当然是。 main()是对任何全局代码的调用 - 基本上,当您在网页中加载脚本并执行时(是的,这可能会发生多次(。或者你告诉节点执行的全局程序。一旦代码完成运行,它确实会被弹出堆栈,正如你在谈话的动画中很好地看到的那样。它不会"继续运行",因为这会阻塞事件循环。

我在这里的推理是,如果是这样,那么JS程序将是完整的,并且不会发生回调。

不。脚本可能已经完成,是的,但您的程序(浏览器环境、节点等(尚未完成。事件循环仍在旋转(或者,确切地说:刚刚开始旋转(。

事件循环将查看正在进行的异步任务(XHR、超时、文件 IO 等(,并注意到仍有一些工作。程序不退出。一旦这些任务中的一个(或多个(完成,它们就会将其回调放入回调队列中,事件循环在其中拾取回调,并通过在全新的调用堆栈上执行它进行处理。当该堆栈再次为空时,事件循环将重新处于控制状态,并从队列中获取回调,直到它为空。然后,它查看是否仍有正在进行的任务(其中一个回调可能已经产生了新的任务(,并且只有当没有任务时,程序才真正结束,全局环境可以被破坏。

所以是的,在javascript程序的执行中确实有调用堆栈为空的时候,只有事件循环在快乐地旋转 - 实际上,大多数时候都是这种情况。

正如你所说,main(( 是全局执行上下文。它仍然活着,直到:

  • 如果您使用的是浏览器,则关闭该选项卡
  • 如果您在服务器上(如节点(,则会终止进程
  • 选项卡/进程崩溃

因此,除非发生上述用例之一,否则运行时仍然处于活动状态,事件循环(将处理任务队列(也是如此。

相关文章: