我终于搞懂了 Event Loop(宏任务 / 微任务)

一、为什么要学这个

  • 我在哪遇到这个问题

    • 写 Vue / React 时,经常看到:

      • nextTick
      • Promise.then
      • setTimeout
    • 但执行顺序总是"感觉对了,但解释不清楚"

  • 真实踩坑场景

    javascript 复制代码
    console.log(1)
    
    setTimeout(() => {
      console.log(2)
    })
    
    Promise.resolve().then(() => {
      console.log(3)
    })
    
    console.log(4)

👉 我当时:知道答案是 1 4 3 2,但不知道为什么


  • 为什么必须搞懂(工程意义)

    • UI 更新为什么"延迟一拍"
    • Vue 的 nextTick 为什么这么设计
    • 为什么有时候 setTimeout 会"卡"
    • 如何避免"状态更新错乱"

👉 本质一句话:

❗Event Loop 决定了你代码的"执行顺序"和"时机控制"


二、我一开始的理解(错误认知)

👉 这是我当时非常真实的理解(现在看是错的)

  • 我原来以为:

    "JS 是单线程,所以代码就是从上到下执行,遇到异步就丢到后面"

  • 我对宏任务 / 微任务的理解:

    • 宏任务:大任务(setTimeout)
    • 微任务:小任务(Promise)

👉 问题来了:

  • ❓ 为什么 Promise 一定比 setTimeout 先执行?
  • ❓ "小任务"凭什么优先?
  • ❓ DOM 更新为什么在某些时机才发生?

👉 最致命的问题:

❗我不知道"什么时候清空微任务队列"


三、核心概念拆解(用人话讲清楚)

我们不用官方定义,直接用"人话"👇


🧠 Event Loop 本质

👉 可以理解为:

一个无限循环的"调度器"

它一直在做这件事:

markdown 复制代码
1. 执行一个宏任务
2. 清空所有微任务
3. 更新 UI(浏览器)
4. 进入下一轮

📦 宏任务(Macrotask)

👉 就是"一整轮任务"

常见:

  • script(整段代码)
  • setTimeout
  • setInterval
  • I/O

👉 类比:

一次"完整的工作流程"


⚡ 微任务(Microtask)

👉 插队任务(优先级极高)

常见:

  • Promise.then
  • MutationObserver
  • Vue 的 nextTick(优先用微任务)

👉 类比:

"老板突然插话:这个先做一下"


🧩 关键区别(核心)

类型 何时执行
宏任务 一轮一轮执行
微任务 当前宏任务结束后 立刻清空

👉 关键一句话:

❗每执行完一个宏任务,必须把微任务全部执行完,才进入下一个宏任务


四、运行机制 / 原理(重点)

我们用刚才那段代码来"拆执行过程"👇


五、代码验证(重点🔥)

javascript 复制代码
console.log(1)

setTimeout(() => {
  console.log(2)
})

Promise.resolve().then(() => {
  console.log(3)
})

console.log(4)

🧠 执行过程(逐步推导)


🟢 第一步:执行主线程(宏任务 #1)

arduino 复制代码
console.log(1) // 输出 1
scss 复制代码
setTimeout(...) // 放入宏任务队列
javascript 复制代码
Promise.then(...) // 放入微任务队列
arduino 复制代码
console.log(4) // 输出 4

👉 此时:

  • 宏任务队列:setTimeout
  • 微任务队列:Promise.then

🟡 第二步:清空微任务队列

arduino 复制代码
console.log(3)

👉 输出:

复制代码
3

🔵 第三步:进入下一轮 Event Loop

执行宏任务:

arduino 复制代码
setTimeout -> console.log(2)

👉 输出:

复制代码
2

✅ 最终结果

复制代码
1
4
3
2

六、总结规律

👉 给你一套"可复用判断模型"(非常关键)


🧠 判断顺序口诀

markdown 复制代码
1. 先执行同步代码(主线程)
2. 遇到宏任务 → 丢到宏任务队列
3. 遇到微任务 → 丢到微任务队列
4. 当前宏任务执行完
5. 立刻清空所有微任务
6. 再执行下一个宏任务

🎯 一句话总结

❗微任务永远在"当前宏任务结束后、下一个宏任务开始前"执行


🧩 判断技巧(工程实用)

看到代码:

👉 先标记:

  • 同步
  • 微任务
  • 宏任务

👉 再按这个顺序排:

复制代码
同步 → 微任务 → 宏任务

七、常见误区


❌ 误区 1:微任务 = 更快执行

👉 错!

微任务不是"更快",而是"更早"


❌ 误区 2:setTimeout 是"立即执行"

scss 复制代码
setTimeout(fn, 0)

👉 实际:

❗只是"尽快进入下一轮"


❌ 误区 3:多个 Promise 是并行执行

javascript 复制代码
Promise.resolve().then(() => console.log(1))
Promise.resolve().then(() => console.log(2))

👉 实际:

❗是按顺序进入微任务队列,一个一个执行


八、我现在的理解

👉 从"模糊"到"清晰"的变化:


❌ 以前

  • Promise 比 setTimeout 快(但不知道为什么)
  • nextTick 是"异步优化"(但不理解本质)

✅ 现在

👉 我会这样理解:

Event Loop 是一个"宏任务驱动 + 微任务插队"的调度系统


👉 更工程化一点:

  • 宏任务:控制节奏(tick)
  • 微任务:做"收尾 / 修正 / 合并更新"

👉 这就是为什么:

  • Vue 要用 nextTick
  • React 要做批处理(batch update)

九、扩展方向

如果你已经理解到这里,可以继续深入👇


🚀 1. Vue 的 nextTick

👉 本质:

利用微任务,在 DOM 更新后执行回调


🚀 2. React Scheduler

👉 本质:

控制任务优先级 + 可中断渲染


🚀 3. 浏览器渲染时机

  • 微任务之后
  • 宏任务之间

🚀 4. Node.js Event Loop(更复杂)

  • 不同阶段(timers / poll / check)

最后一刀总结(帮你彻底记住)

❗Event Loop = 宏任务一轮一轮跑 + 每轮结束必须清空微任务


如果你愿意,下一篇我可以帮你写一个"更狠的"👇

👉 《我终于搞懂了 Vue nextTick 为什么一定要用微任务》

这个会直接把你带到"框架设计层"。

相关推荐
ZC跨境爬虫21 小时前
3D 地球卫星轨道可视化平台开发 Day10(交互升级与接口溯源)
前端·javascript·3d·自动化·交互
恋猫de小郭21 小时前
WasmGC 是什么?为什么它对 Dart 和 Kotlin 在 Web 领域很重要?
android·前端·flutter
新酱爱学习21 小时前
从一次 OpenClaw 请求抓包,聊聊 Skill 的运行原理
前端·人工智能·mcp
慕斯fuafua21 小时前
CSS——弹性盒子
前端·css
M ? A21 小时前
Vue Transition 组件转 React:VuReact 怎么处理?
前端·javascript·vue.js·经验分享·react.js·面试·vureact
小江的记录本21 小时前
【分布式】分布式一致性协议:2PC/3PC、Paxos、Raft、ZAB 核心原理、区别(2026必考Raft)
java·前端·分布式·后端·安全·面试·系统架构
huangql52021 小时前
CSS布局 (三):浮动——从文字环绕到多列布局
前端·javascript·css
LaughingZhu21 小时前
Product Hunt 每日热榜 | 2026-04-20
前端·数据库·人工智能·经验分享·神经网络
开开心心就好21 小时前
这款PPT计时工具支持远程控制功能
前端·科技·游戏·edge·pdf·全文检索·powerpoint
BangD21 小时前
前端elementUI el-form个别字段增加校验
前端·vue.js·elementui