事件循环的任务优先级由队列类型和执行时机天然决定:微任务总在当前宏任务结束后、下一个宏任务开始前被清空,因此比宏任务更早执行;浏览器采用多优先级队列模型,包括微任务、交互、动画帧、延时、网络等队列,各自按固定顺序调度。

事件循环的任务优先级不是靠“设置等级”实现的,而是由队列类型和执行时机天然决定的:微任务总在当前宏任务结束后、下一个宏任务开始前被清空,因此它比宏任务“更早拿到执行权”。这种机制是浏览器和 Node.js 的底层约定,无需手动配置优先级数值。
微任务 vs 宏任务:谁先谁后,为什么
每次事件循环只取一个宏任务执行(如 setTimeout 回调、用户点击事件、脚本初始化),但一旦该宏任务执行完毕,引擎会立刻暂停,转而一次性执行完所有已排队的微任务,包括中途新加入的。这意味着:
- Promise.then、queueMicrotask、MutationObserver 回调都属于微任务,它们不排队等下一轮,而是“插在本轮末尾”
- setTimeout、setInterval、I/O 完成回调、UI 渲染属于宏任务,必须等到当前微任务队列彻底清空后才轮到
- 即使 setTimeout(0) 被注册得非常早,它的回调仍要排在所有微任务之后
浏览器实际调度不止两级:多队列分层模型
现代浏览器(如 Chromium)内部采用多优先级队列系统,并非只有“宏/微”两档。典型顺序从高到低为:
用于 inference.sh 的 JavaScript/TypeScript SDK,可运行 AI 应用、构建代理、集成 150+ 模型。包名:@inferencesh/sdk(npm install),完整 TypeScript 支持。
- 微任务队列:最高优先级,保障状态一致性(如 Promise 链收尾)
- 交互队列:处理 click、scroll、input 等用户操作,保证响应及时
- 动画帧队列:requestAnimationFrame 回调,紧邻渲染阶段,适合读写 DOM 尺寸
- 延时队列:setTimeout/setInterval,按设定时间触发
- 网络队列:fetch 响应回调,受网络延迟和资源限制影响
注意:微任务虽高优,但它不会打断正在运行的交互事件;而交互事件也**不会中断微任务执行**——两者在事件循环中是串行协作关系。
怎么用对优先级,而不是滥用
关键不是“让任务更快”,而是“让它在最合适的时机运行”:
- 需要确保 DOM 已更新、但又不想等下一帧 → 用 queueMicrotask
- 需要测量布局后渲染效果(比如获取元素高度)→ 用 requestAnimationFrame
- 需要真正延后到浏览器空闲时段 → 用 requestIdleCallback(非标准但广泛支持)
- 耗时计算或大量数据处理 → 别卡主线程,移进 Web Worker
Python asyncio 的对比参考
asyncio 没有内置优先级调度,但可通过 asyncio.PriorityQueue 手动构造优先级逻辑:数字越小,优先级越高。例如把告警任务设为优先级 0,用户请求为 1,后台同步为 2。不过要注意,这仍是“逻辑优先级”,实际执行仍依赖事件循环是否主动让出控制权(比如 await asyncio.sleep(0))。










