事件循环先执行一个宏任务,结束后立即按序清空所有微任务,再取下一个宏任务;同步代码优先执行,异步操作仅注册回调,微任务在宏任务结束后即时、全部、顺序执行完毕。

理清 macro 与 micro 的顺序,关键不是背列表,而是抓住事件循环的执行节奏:每次只取一个宏任务执行,它一结束,立刻、全部、按序执行当前所有微任务,之后才去拿下一个宏任务。
先跑完同步代码,再看“谁排队”
整段 <script> 是第一个宏任务。里面的代码从上到下同步执行,遇到异步操作时,不等结果,只做两件事:
- setTimeout/setInterval/UI事件 → 注册回调,进宏任务队列
- Promise.then/await后代码/queueMicrotask → 注册回调,进微任务队列
注意:此时微任务还没执行,只是“登记在册”。
宏任务一收尾,微任务全清空
同步代码跑完,调用栈变空,事件循环立刻转向微任务队列:
用于 inference.sh 的 JavaScript/TypeScript SDK,可运行 AI 应用、构建代理、集成 150+ 模型。包名:@inferencesh/sdk(npm install),完整 TypeScript 支持。
- 按注册顺序(先进先出)逐个取出并执行
- 执行过程中如果又产生新微任务(比如某个
.then里又写了个Promise.resolve().then(...)),也立刻加入队尾,并在本轮继续执行 - 直到微任务队列彻底为空,才停止
这个“清空”动作是强制且即时的,不会跨轮次留尾巴。
渲染可能插在中间,但不影响任务顺序
微任务清空后,浏览器通常会进行一次 UI 渲染(重排+重绘),但这属于渲染线程行为,JS 主线程并不等待它完成。下一轮事件循环直接从宏任务队列取下一个任务——可能是 setTimeout 回调、用户点击事件,或另一个 script 标签。
- 渲染不是 JS 任务,也不进任何队列
- 它发生在“微任务清空后、下一个宏任务开始前”这个间隙,但不是事件循环的必经步骤(比如后台标签页可能跳过)
常见误区提醒
容易混淆的点其实就几个:
-
async/await 不是新任务类型:它只是 Promise 语法糖,
await后面的代码相当于.then,属于微任务 -
setImmediate 和 process.nextTick 是 Node.js 特有,浏览器环境不存在;且
nextTick在 Node 中优先级高于 Promise - MutationObserver 是微任务,常用于监听 DOM 变化,适合需要比 Promise 更早响应的场景

















