彻底搞懂 Event Loop!这篇文章帮你一次性吃透宏任务、微任务、执行顺序

Event Loop(事件循环) 是 JavaScript 执行机制里的核心知识点。不管是前端面试还是日常开发,只要涉及异步,就绕不开它。

这篇文章不玩高深术语,用一套真实示例,带你搞懂:

  • 同步任务宏任务微任务 到底是什么
  • 它们的执行顺序和优先级
  • 最后特别提醒:Promise.resolve().then() 到底哪个才是微任务?

🧵 为什么需要 Event Loop?

JS 是单线程,意味着同一时刻只能执行一件事。

比如:

js 复制代码
console.log('A');
console.log('B');
console.log('C');

执行结果必然是:

css 复制代码
A
B
C

这就是同步任务:顺序执行,执行完才往下走。

但是,现实开发中需要执行很多耗时任务(比如网络请求、定时器)。如果都用同步执行,页面直接卡死,体验没法要。

所以浏览器和 Node 设计了异步队列 + Event Loop,先把耗时任务挂起,空闲时再回头执行。


🗂️ 同步任务、宏任务、微任务,怎么分?

先看个对比表:

类型 代表
同步任务 普通函数、console.log、函数调用
宏任务(Macrotask) 整个 <script>setTimeoutsetIntervalsetImmediateMessageChannel(浏览器)、I/O(Node)
微任务(Microtask) Promise.then()MutationObserverqueueMicrotaskprocess.nextTick(Node 专属)

执行顺序口诀:

一个宏任务 → 执行同步任务 → 清空微任务 → 执行下一个宏任务 → 循环


✅ 浏览器执行顺序经典示例

来看个最典型的组合拳:

js 复制代码
console.log('代码开始');

setTimeout(() => {
  console.log('这是 setTimeout 回调');
}, 0);

Promise.resolve().then(() => {
  console.log('这是 promise 的回调');
});

console.log('代码结束');

🧐 输出结果:

arduino 复制代码
代码开始
代码结束
这是 promise 的回调
这是 setTimeout 回调

执行过程拆解:

  1. <script> 整个文件就是一个宏任务,先跑同步代码。
  2. setTimeout 是下一个宏任务,排到队列后面。
  3. Promise.then 是微任务,会在本轮宏任务跑完后立刻执行。
  4. 所以输出顺序是:同步 → 微任务 → 下一个宏任务

❗ 重点:Promise.resolve() 本身不是微任务!

超多人搞错,以为 Promise.resolve() 本身是微任务,其实不是!

来看个例子:

js 复制代码
console.log('程序启动');

const p1 = Promise.resolve('第一个 Promise');
const p2 = Promise.resolve('第二个 Promise');
const p3 = new Promise(resolve => {
    console.log('执行 p3 构造函数');
    resolve('第三个 Promise');
});

p1.then(value => console.log(value));
p2.then(value => console.log(value));
p3.then(value => console.log(value));

setTimeout(() => {
    console.log('第一波 setTimeout');
    const p4 = Promise.resolve('第四个 Promise');
    p4.then(value => console.log(value));
}, 0);

setTimeout(() => {
    console.log('第二波 setTimeout');
}, 0);

console.log('程序结束');

执行顺序:

javascript 复制代码
程序启动
执行 p3 构造函数
程序结束
第一个 Promise
第二个 Promise
第三个 Promise
第一波 setTimeout
第四个 Promise
第二波 setTimeout

🔑 为什么?

  • Promise.resolve() 只是返回一个已确定状态的 Promise,不会产生微任务。

  • 真正触发微任务队列的是 .then() 的回调!

  • 所以这段里:

    • 同步任务先跑完:程序启动执行 p3 构造函数程序结束
    • 再清空微任务队列:第一个 Promise第二个 Promise第三个 Promise
    • 然后执行第一个 setTimeout(宏任务):第一波 setTimeout,里面的 .then() 会生成一个新的微任务:第四个 Promise
    • 最后执行第二个 setTimeout第二波 setTimeout

🧬 MutationObserver:监听 DOM 改变的微任务

浏览器里,MutationObserver 也属于微任务。看个示例:

js 复制代码
const target = document.createElement('div');
document.body.appendChild(target);

const observer = new MutationObserver(() => {
  console.log('微任务: MutationObserver 回调执行');
});

observer.observe(target, { attributes: true, childList: true });

target.setAttribute('data-role', '123');
target.appendChild(document.createElement('span'));

这里修改了 target 的属性和子元素,MutationObserver 会把回调放进微任务队列,在本轮宏任务执行完后跑。


⚡ Node.js 专属:process.nextTick 比普通微任务还快!

Node.js 里还有个专属:process.nextTick,它优先级比普通微任务还高。

js 复制代码
console.log('启动');

process.nextTick(() => {
  console.log('执行 process.nextTick');
});

Promise.resolve().then(() => {
  console.log('执行 Promise.then');
});

setTimeout(() => {
  console.log('执行 setTimeout');
  Promise.resolve().then(() => {
    console.log('setTimeout 中的 Promise');
  });
}, 0);

console.log('收尾');

🧐 输出结果:

javascript 复制代码
启动
收尾
执行 process.nextTick
执行 Promise.then
执行 setTimeout
setTimeout 中的 Promise

✏️ queueMicrotask:手动插个微任务

需要自己把任务插进微任务队列?用 queueMicrotask

js 复制代码
console.log('准备执行');

queueMicrotask(() => {
  console.log('这是 queueMicrotask 回调');
});

console.log('执行完同步任务');

输出:

复制代码
准备执行
执行完同步任务
这是 queueMicrotask 回调

Promise.then 一样效果,都会在本轮宏任务执行完后立刻跑。


🗂️ 总结:执行顺序记住这张表

优先级 队列
🥇 最高 process.nextTick(Node 专属)
🥈 第二 Promise.thenMutationObserverqueueMicrotask
🥉 最后 宏任务:setTimeoutsetIntervalI/O

顺序一定是:

  • 当前宏任务执行完 → 清空所有微任务
  • 再执行下一个宏任务
  • 循环往复

🚀 最后的金句

Promise.resolve() 只是创建了一个已确定状态的 Promise,本身不是微任务。只有调用 .then() 后,回调才会排进微任务队列!

别再搞混了!

面试题里很多顺序题,考点就是这里。

相关推荐
yuanyxh4 小时前
Mac 软件推荐
前端·javascript·程序员
万少4 小时前
AtomCode开发微信小程序《谁去呀》 全流程
前端·javascript·后端
某人辛木4 小时前
Web自动化测试
前端·python·pycharm·pytest
Kagol5 小时前
Superpowers GSD gstack AgentSkills深度测评
前端·人工智能
excel6 小时前
JavaScript 字符串与模板字面量:从表象到本质理解
前端
京东云开发者6 小时前
当AI成为导演-如何用AI创作动漫短剧
前端
李白的天不白7 小时前
使用 SmartAdmin 进行前后端开发
java·前端
乘风gg7 小时前
🤡PUA AI Coding 工具 的 10 条终极语录
前端·ai编程·claude
学Linux的语莫7 小时前
Vue 3 入门教程
前端·javascript·vue.js
怕浪猫7 小时前
第一章、Chrome DevTools Protocol (CDP) 详解
前端·javascript·chrome