【JS】JavaScript 事件循环(Event Loop)、宏任务与微任务指南

14 阅读2分钟

🌐 事件循环的本质

1. 谁在控制事件循环?

  • 不是JavaScript语言本身,而是运行环境(浏览器/Node.js)的内置机制。
  • 就像操作系统的"任务调度器",自动管理任务执行顺序。

2. 为什么需要事件循环?

场景无事件循环有事件循环
同步任务直接阻塞执行直接执行
异步任务卡死页面通过队列非阻塞处理

🔧 运行环境对比

特性浏览器事件循环Node.js事件循环
实现方浏览器渲染引擎(如V8)libuv库
微任务Promise.then/MutationObserverprocess.nextTick/Promise
宏任务setTimeout/UI渲染setImmediate/文件I/O

⚙️ 事件循环完整流程

image.png

关键阶段(浏览器)

  1. 同步代码执行
  2. 微任务清空(VIP通道)
    • Promise.then
    • MutationObserver
    • queueMicrotask
  1. 渲染DOM(如有需要)
  2. 宏任务执行(普通通道)
    • setTimeout
    • 事件回调
    • AJAX回调

💡 深度理解技巧

1. 延迟0ms的setTimeout

setTimeout(() => console.log("宏任务"), 0);
Promise.resolve().then(() => console.log("微任务"));
console.log("同步");
// 输出顺序:同步 → 微任务 → 宏任务
  • 0ms不是立即执行,而是最快进入宏任务队列

2. 微任务嵌套

Promise.resolve().then(() => {
  console.log("微任务1");
  Promise.resolve().then(() => console.log("嵌套微任务"));
});
  • 微任务执行期间产生的新微任务会立即执行,不会等到下一轮循环

🚨 常见误区澄清

误区1:"事件循环是JS引擎的一部分"

  • ✅ 事实:JS引擎(如V8)只负责执行代码,事件循环由宿主环境实现

误区2:"微任务比宏任务快"

  • ✅ 更准确:微任务在同一轮循环中优先执行

误区3:"requestAnimationFrame是宏任务"

  • ✅ 事实:属于渲染阶段的任务,既不是宏任务也不是微任务

🎯 面试黄金题

题1:说出下面代码的输出顺序

console.log(1);

setTimeout(() => console.log(2), 0);

Promise.resolve()
  .then(() => console.log(3))
  .then(() => console.log(4));

console.log(5);

答案:1 → 5 → 3 → 4 → 2

题2:如何实现优先执行的微任务?

// 方法1:Promise.resolve()
Promise.resolve().then(fn);

// 方法2:queueMicrotask(更语义化)
queueMicrotask(fn);

📜 终极总结表

概念触发方式执行时机典型API
同步任务直接调用立即执行console.log
微任务异步回调同步代码后立即执行Promise.then
宏任务事件/定时器微任务队列清空后执行setTimeout
渲染任务浏览器自动调度微任务之后、宏任务之前requestAnimationFrame

记忆口诀

"同步先走,微务插队,宏任务排队,循环不累"
(同步 → 微任务 → 渲染 → 宏任务 → 循环...)