现代浏览器事件循环采用多队列分级机制:微任务队列优先级最高且必须存在,每次宏任务后立即清空;交互队列次高,保障用户操作及时响应;延时队列、I/O队列、渲染队列等按浏览器策略动态调度,优先级低于交互队列。

宏任务不再统一归入一个“宏队列”,而是按来源拆分为多个独立队列,各自拥有明确优先级。微任务队列始终最高,其余队列的执行顺序由浏览器动态决定,但存在稳定的相对层级。
微任务队列:唯一强制高优队列
规范要求浏览器必须实现且仅有一个微任务队列,其优先级绝对高于所有其他类型任务。它在每次宏任务执行完毕后立即清空——包括执行过程中新加入的微任务(如 Promise.then 里再调用 queueMicrotask)。这意味着只要微任务队列非空,主线程就不会取下一个宏任务。
交互队列:用户响应优先级最高
用户触发的操作(点击、输入、滚动、键盘事件等)回调被放入交互队列,该队列在非微任务中优先级最高。浏览器会优先调度它,确保界面交互不卡顿。例如,一个正在执行的 setTimeout 回调若被用户点击打断,点击事件的处理会插队执行(实际取决于渲染帧节奏,但调度倾向明确)。
延时队列:setTimeout/setInterval 的归属
定时器回调(包括 setTimeout(fn, 0))被放入延时队列,优先级低于交互队列,与 I/O 队列(如 fetch 完成回调)、渲染相关队列(如 requestAnimationFrame)处于相近但不完全等同的层级。Chrome 当前版本(如 110+)中,同一类延时任务严格遵循 FIFO;不同类任务间无固定先后,输出顺序常取决于代码注册顺序而非“谁更早到期”。
其他队列:按需调度,避免饿死
网络请求完成、文件读写、requestAnimationFrame 等各自进入对应队列。浏览器可动态调整它们的优先级——比如页面加载初期提升解析和脚本执行权重,空闲时加快后台 fetch 处理。这种弹性调度由引擎内部策略控制,开发者无法直接干预,但可通过 requestIdleCallback 主动让出时间片。


















