执行上下文与事件循环是上下游协作关系:执行上下文负责代码如何运行,事件循环决定何时运行哪段代码;前者管理同步执行现场,后者在执行栈为空时调度微任务和宏任务。

JavaScript 执行上下文和事件循环不是并列概念,而是紧密协作的上下游关系:执行上下文负责“怎么运行一段代码”,事件循环负责“什么时候运行哪段代码”。它们共同支撑起 JavaScript 单线程下的同步与异步协同。
执行上下文是任务执行的“现场”
每次函数调用或脚本启动,引擎都会创建一个执行上下文(EC),它包含:
– 变量环境(var、函数声明)
– 词法环境(let/const/class)
– this 绑定
– 作用域链(决定变量查找路径)
全局 EC 在页面加载时创建,函数 EC 在调用时动态生成,并压入执行栈顶部——此时它就是“正在运行的执行上下文”。
执行栈控制同步流程,为事件循环让出时机
执行栈(Call Stack)是一个后进先出结构,只管理同步代码的执行顺序:
– 函数调用 → 新 EC 入栈 → 成为当前上下文
– 函数返回或执行完毕 → EC 出栈 → 控制权交还上层
– 栈一旦清空,主线程就空闲了
这个“空闲状态”正是事件循环被触发的唯一条件。没有栈空,事件循环不会介入;栈不空,所有异步回调都只能排队等待。
事件循环按规则调度新上下文入栈
当执行栈为空,事件循环开始工作,按固定优先级调度任务:
– 先检查微任务队列(Promise.then、MutationObserver 等),一次性清空所有待执行微任务
– 每个微任务执行时,都会创建自己的执行上下文并入栈,执行完立即出栈
– 微任务队列清空后,再从宏任务队列取一个(如 setTimeout 回调、script 标签整体、UI 渲染等)
– 宏任务执行同样会创建新 EC 入栈,执行中可能又产生新的微任务或宏任务,继续进入下一轮循环
三者配合的关键节奏
整个流程不是交替切换,而是“同步压栈 → 栈空触发 → 微任务批量入栈执行 → 宏任务单个入栈执行 → 再次栈空…”的闭环:
– 同一宏任务内产生的 Promise.then 会进入本轮微任务队列,立刻执行
– setTimeout 的回调属于下一个宏任务,必须等当前宏任务 + 所有微任务全部结束才轮到
– 每次新任务执行,都意味着一个新的执行上下文被创建、入栈、运行、销毁
这种设计保证了异步逻辑可预测,也避免了微任务无限嵌套阻塞宏任务
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











