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

事件循环中addEventListener回调与微/宏任务的优先级及执行阶段

浏览器事件循环优先级问题

代码示例

console.log("11111");

setTimeout(() => {
  console.log("22222");
}, 5000);

Promise.resolve().then(() => {
  console.log("33333");
});

document.getElementById("test").addEventListener("click", () => {
  console.log("44444 +");
});

// 10秒同步延迟,留出时间触发点击事件
const syncWait = (ms) => {
  const end = Date.now() + ms;
  while (Date.now() < end) continue;
};
syncWait(10000);

console.log("55555");

实际输出

11111
55555
33333
44444 +
22222

问题

在浏览器事件循环中,通过addEventListener触发的回调函数,与微任务队列、宏任务队列回调的精确优先级是怎样的?换句话说,它们分别在事件循环的哪个具体阶段从各自队列中出队执行?

解答

浏览器事件循环的核心执行顺序和各任务的阶段划分如下:

  1. 优先执行所有同步代码:调用栈中的同步任务会按顺序全部执行完毕,比如示例里的console.log("11111")、10秒同步延迟、console.log("55555")都属于这一步。
  2. 一次性清空微任务队列:同步代码执行完、调用栈清空后,会立刻执行微任务队列里的所有任务,Promise.resolve().then()这类回调就属于微任务,所以示例中的33333会紧跟同步代码输出。
  3. 分阶段处理宏任务队列:微任务全部处理完成后,才会进入事件循环的各个阶段处理宏任务,不同类型的宏任务对应不同的执行阶段:
    • addEventListener触发的用户交互回调(比如click)属于事件触发阶段的宏任务,这个阶段在定时器阶段之前,所以已触发的交互回调会比定时器回调先执行。
    • setTimeout这类定时器回调属于定时器阶段的宏任务,会在事件触发阶段之后处理。

对应示例场景:同步代码执行的10秒内,点击test元素会把click回调加入事件触发宏任务队列;setTimeout到5秒时,其回调会被加入定时器宏任务队列。同步代码跑完后,先执行微任务的33333,接着事件循环先处理事件触发阶段的click回调输出44444 +,最后处理定时器阶段的22222。


内容的提问来源于stack exchange,提问作者Sha'an

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 10:55:00