事件循环按同步→微任务→宏任务的固定顺序执行:同步代码立即执行;微任务在每轮宏任务后清空;宏任务队列fifo,每轮仅取一个;异步串行需用await、promise链等主动建依赖。

事件循环本身不“保证”你写的异步代码按某种主观顺序执行,而是通过一套确定的调度规则,让不同任务类型在固定节奏下有序出场。真正起作用的是任务分类、优先级设定和每轮循环的执行节拍。
同步代码永远最先执行
所有直接写的语句(比如 console.log、变量赋值、函数调用)都属于同步任务,会立刻进入调用栈,逐行执行完才放手。这是整个顺序的起点,没有例外。
微任务总在宏任务之前清空
一旦同步代码跑完,引擎不会马上去取下一个宏任务,而是先检查微任务队列,并把当前所有微任务按注册顺序一次性执行完——中间不插入任何宏任务。
- Promises 的 .then/.catch/.finally 回调
- queueMicrotask() 注册的函数
- MutationObserver 的回调
哪怕你在 setTimeout 里 new Promise().then(...),那个 then 也会等当前宏任务结束、微任务清空后立刻执行,而不是等到下一轮 setTimeout。
每次只取一个宏任务,且严格按队列顺序
宏任务队列是先进先出的,但事件循环每轮只从中取出最老的一个执行:
- 全局脚本(第一轮的宏任务)
- setTimeout / setInterval 回调
- I/O 完成回调、UI 渲染(浏览器端)
- requestAnimationFrame(浏览器专属宏任务)
这就解释了为什么两个 setTimeout(..., 0) 总是第一个先执行、第二个后执行——它们被依次推入宏任务队列,不会并发抢占。
想控制多个异步步骤的先后,得靠代码结构
事件循环不管你的业务逻辑是否“应该串行”,它只认任务类型。要让异步操作严格按序执行,必须主动建立依赖关系:
- 用 await 配合 for...of:每次迭代都等前一个 Promise settle 后再开始下一个
- 用 Promise 链:.then(() => step1()).then(() => step2()),每个 then 返回的新 Promise 构成执行链条
- 避免在循环里直接写多个 setTimeout 或并列 .then,那样只是并发注册,执行顺序取决于完成时间,不可控
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











