事件循环是javascript运行时内置的调度机制,用于协调同步任务、异步回调与ui渲染;其核心由调用栈、微任务队列(如promise.then)和宏任务队列(如settimeout)组成,执行顺序为:先清空同步代码→一次性执行所有微任务→(浏览器)可能渲染→执行一个宏任务→循环。

事件循环不是一段代码,也不是一个 API,它是 JavaScript 运行时(浏览器或 Node.js)内置的调度机制,用来协调同步任务、异步回调和 UI 渲染的执行节奏。它的存在,是因为 JS 主线程只能干一件事,但现实中的操作——比如点击、加载图片、等待网络响应——又不能让整个页面卡住。所以事件循环本质上是在“排队 + 切换 + 优先级判断”。
它由三块关键部件组成
理解事件循环,先记住这三个角色如何配合:
- 调用栈(Call Stack):同步代码的执行地。函数调用就压栈,执行完就出栈。栈空了,才轮到队列里的任务上场。
-
微任务队列(Microtask Queue):存放高优先级的异步回调,比如
Promise.then、queueMicrotask、MutationObserver。它不是“一个一个取”,而是每次栈空后一次性清空全部。 -
宏任务队列(Macrotask Queue):存放低一级但更常见的异步任务,比如
setTimeout、setInterval、DOM 事件、fetch回调、script整体代码。每次只从中取出一个执行。
一次循环的真实执行顺序
不是“先宏后微”或“交替执行”,而是有严格步骤:
- 执行当前所有同步代码(直到调用栈彻底清空)
- 立即检查并执行完所有微任务(哪怕新微任务在执行中产生,也会被追加并继续执行)
- (在浏览器中)可能触发一次 UI 渲染(如样式更新、重排重绘)
- 从宏任务队列头部取出一个任务,推入调用栈执行
- 回到第一步,开始下一轮
为什么 Promise 总比 setTimeout 快?
这不是因为 Promise “更快”,而是因为它们被放进不同队列、遵循不同规则:
-
Promise.resolve().then(...)的回调进入微任务队列,会在当前宏任务结束后立刻执行 -
setTimeout(..., 0)的回调进入宏任务队列,得等当前宏任务 + 所有微任务走完,再等下一个宏任务轮到它 - 所以即使时间设为 0,
setTimeout也一定晚于同轮次的Promise.then
它不是 JS 引擎写的,而是运行环境提供的
JS 引擎(如 V8)只负责执行代码、管理调用栈和堆;而事件循环本身,由宿主环境实现:
- 浏览器中,由渲染引擎(如 Blink)和定时器/网络模块协同维护
- Node.js 中,则由
libuv库统一调度 I/O、定时器、子进程等 - 这意味着不同环境的细节可能略有差异(比如 Node 中
process.nextTick优先级高于 Promise),但核心模型一致
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











