【问题标题】:Does the JS callstack always have at least one frame?JS 调用栈是否总是至少有一帧?
【发布时间】:2015-02-16 05:19:41
【问题描述】:

我最近看到了presentation on the JS event loop,坦率地说,它很棒,但我现在有一个关于 JS 调用堆栈的挥之不去的问题。如果您将全局执行上下文视为 main(),那么 main() 是否永远不会被解析?我的理由是,如果是,那么 JS 程序将是完整的,并且不会发生回调。

--编辑

我在这里的主要兴趣是调用堆栈如何表示,与回调队列相关。如果说事件循环在将新帧推入堆栈之前等待调用堆栈为空,那么循环将等待直到程序完成,并且回调不会有任何效果。

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

【问题讨论】:

  • 该演示文稿是否在其他地方可用,只有幻灯片?我找到了transscript,但要回答您的问题,我需要查看幻灯片。或者您可以链接到演示文稿的相关部分?
  • 他在 10 分钟左右开始谈论调用堆栈。

标签: javascript callstack event-loop


【解决方案1】:

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

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

main() 永远不会解决吗?

当然是。 main()invocation of any global code - 基本上,当您在网页中加载脚本并执行时(是的,这可能会发生多次)。或者你告诉节点执行的全局程序。一旦该代码完成运行,它确实会从堆栈中弹出,正如您在会谈动画中所看到的那样。它不会“继续运行”,因为这会阻塞事件循环。

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

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

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

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

【讨论】:

    【解决方案2】:

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

    • 如果您在浏览器中,则关闭标签页
    • 如果您在服务器(如节点)上,则终止该进程
    • 选项卡/进程崩溃

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

    【讨论】:

    • 谢谢!所以,我想这意味着回调队列等待将一个新帧推送到调用堆栈,直到只剩下一个 main() 帧。
    • 事实上,这是一个事件循环,负责将任务队列中剩余的回调推送到 main() 如果 main() 死了,回调将无处可去——除非浏览器 (或服务器,或您所处的任何环境)在进程死亡时取消了与进程相关的现有计时器(这个我不知道确切)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-14
    • 1970-01-01
    • 2015-09-22
    • 1970-01-01
    • 2013-11-04
    • 1970-01-01
    相关资源
    最近更新 更多