You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

事件循环(Event Loop)中setTimeout等异步API执行优先级差异原因

为什么setTimeout、Promise.then、requestAnimationFrame的异步回调执行优先级有差异

这三类回调的优先级差异本质是JavaScript事件循环对不同异步任务的队列划分和执行规则导致的,具体可以按所属任务队列的优先级排序理解:

  • 微任务队列 优先级最高:Promise.then的回调属于微任务,规则是当前上下文的所有同步代码执行完毕后,会立刻清空整个微任务队列,不会等待渲染或其他宏任务执行。
  • 渲染前回调队列 优先级次之:requestAnimationFrame的回调是浏览器专属的渲染前置队列,执行时机在所有微任务清空之后、浏览器执行重绘/重排之前,每轮事件循环最多执行一次该队列的所有回调。
  • 宏任务队列 优先级最低:setTimeout的回调属于宏任务,必须等当前轮次的微任务全部执行完成、渲染阶段的所有回调处理完毕后,才会在下一轮事件循环中被调度执行。

验证代码执行逻辑说明

你给出的代码实际运行的输出顺序是 4 → 5 → 2 → 3 → 1,逐行对应执行逻辑如下:

setTimeout(()=>console.log(1)); // 推入宏任务队列,最后执行
Promise.resolve(2).then(console.log); // 推入微任务队列,同步代码跑完后立刻执行
requestAnimationFrame(()=>console.log(3)); // 推入渲染前置队列,微任务清空后执行
console.log(4); // 同步任务,第一个输出
window.onclick = ()=>console.log(5); // 绑定点击事件回调
window.dispatchEvent(new Event('click')); // 同步触发事件,回调属于同步执行逻辑,第二个输出

执行步骤拆解:

  1. 先执行所有同步代码:输出4,同步触发点击事件输出5,同步阶段结束。
  2. 清空当前微任务队列:执行Promise.then回调,输出2。
  3. 进入浏览器渲染前置阶段:执行requestAnimationFrame回调,输出3。
  4. 本轮事件循环结束,进入下一轮调度,处理宏任务队列中的setTimeout回调,输出1。

内容的提问来源于stack exchange,提问作者trigold

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 02:45:10