在 Event Loop 之前会发生什么

发布: (2026年1月9日 GMT+8 04:13)
4 min read
原文: Dev.to

Source: Dev.to

JavaScript 代码并不是在任务出现在调用栈的那一刻就被引擎本地执行的。大多数文章只关注事件循环(Event Loop)的工作原理,而忽略了开发者编写的指令在到达那一步之前所走的路径。因此,作用域、闭包、暂时性死区(Temporal Dead Zone)以及其他执行细节常常被记忆为一种“技术魔法”。

在这系列短文中,我们追踪从源码输入到实际执行的全过程。为了避免过于深入特定引擎(V8、SpiderMonkey、JavaScriptCore 等)的实现细节,讨论停留在 ECMAScript 262 规范所定义的抽象层次上。

规范有意 将 JavaScript 执行描述为线性的步骤序列——实现细节留给引擎作者自行决定。尽管如此,结合规范本身以及对引擎实现的实际了解,我们仍然可以辨识出四个有条件的阶段:

  • 确定执行环境:Host、Agent、Realm
  • 解析源代码
  • 创建元对象:模块记录(Module Record)/ 脚本记录(Script Record)
  • 程序执行

执行准备阶段

解析(Parsing)和初始化(initialisation)在此进行。引擎会创建必要的内部记录(例如 ScriptRecordModuleRecord),并在任何用户代码运行之前搭建全局环境。

指令执行阶段

引擎遍历已编译的字节码 / 抽象语法树,创建执行上下文(execution contexts),求值表达式,最终执行程序定义的副作用。

执行环境层

规范定义了三个关键层次的执行环境,这些层次必须在任何开发者指令运行之前就已经存在。

Host

执行 JavaScript 代码的外部程序:浏览器、Node.js、Deno 等。

Agent

执行环境的一个隔离部分(独立于其他 Agent),拥有自己的执行上下文栈(Execution Context Stack)和正在运行的执行上下文(Running Execution Context)。例子包括浏览器标签页、Web Worker 或 iframe。

Realm

一个逻辑实体,定义全局对象、全局方法和全局变量,并负责创建全局执行上下文(Global Execution Context)。在 V8 引擎实现中,这对应于 C++ 中的 v8::Context 类:

// Example: creating a new V8 context
v8::Isolate* isolate = ...;
v8::Local context = v8::Context::New(isolate);

理解执行环境的结构及其隔离模型可以解释:

  • 同一浏览器中不同标签页之间不存在竞争条件。
  • 为什么 Worker 无法访问主应用的全局对象和变量。
  • 单一 Host 内部被覆盖的全局 JavaScript 方法的隔离性。
Back to Blog

相关文章

阅读更多 »

JavaScript 中的异步

同步(普通)情况下,只有当前任务完成后,才会开始下一个任务。javascript console.log'One'; console.log'Two'; console.log'Three'; 👉 输出 One Two...