14、✅ 手写 Event Loop 模拟器(理解微任务 / 宏任务调度)

🎯 一、为什么要手写 Event Loop?

  • 大厂面试必问:async/await、Promise、setTimeout 混合输出顺序
  • 源码能力提升:搞懂浏览器/Node.js 的任务调度机制
  • 理解 JS 单线程异步执行本质,为后续自己写任务队列打下基础

🧠 二、Event Loop 核心概念速查

术语 解释
Call Stack 调用栈,JS 执行同步任务的地方
Macro Task 宏任务,如 setTimeout/setInterval/I/O
Micro Task 微任务,如 Promise.then/MutationObserver
Event Loop 事件循环,调度所有任务的"引擎"
  • 执行顺序:主线程同步任务 → 微任务队列 → 宏任务队列
  • 每次执行完一个宏任务后,立即清空所有微任务

🔍 三、常考面试题(输出顺序)

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

输出顺序? 1、4、3、2


✍️ 四、核心思想:模拟微/宏任务队列

  1. 维护两个队列:macroQueuemicroQueue
  2. 每次执行一个 macro 后,依次执行 microQueue 直到清空
  3. 采用递归或循环驱动任务调度

📦 五、简易 Event Loop 模拟器实现

kotlin 复制代码
class EventLoop {
  constructor() {
    this.macroQueue = [];
    this.microQueue = [];
    this.running = false;
  }

  // 加入宏任务
  setMacroTask(fn) {
    this.macroQueue.push(fn);
    this.run();
  }

  // 加入微任务
  setMicroTask(fn) {
    this.microQueue.push(fn);
    this.run();
  }

  run() {
    if (this.running) return;
    this.running = true;

    while (this.macroQueue.length > 0) {
      // 执行一个宏任务
      const macro = this.macroQueue.shift();
      macro();

      // 清空微任务队列
      while (this.microQueue.length > 0) {
        const micro = this.microQueue.shift();
        micro();
      }
    }

    this.running = false;
  }
}

✅ 六、使用示例(验证调度顺序)

arduino 复制代码
const loop = new EventLoop();

console.log(1);

loop.setMacroTask(() => {
  console.log(2);
});

loop.setMicroTask(() => {
  console.log(3);
});

console.log(4);

// 输出:1 4 3 2

🔁 七、进阶模拟 async/await

async/await 本质就是自动拆分为同步 + 微任务

javascript 复制代码
async function test() {
  console.log('a');
  await Promise.resolve();
  console.log('b');
}
test();
console.log('c');
// 输出:a c b
  • await 前为同步,await 后回到微任务

❗ 八、面试陷阱总结

题型 易错点
setTimeout + Promise 谁先输出? Promise 微任务先于 setTimeout 宏任务
多重微任务 一次性全部执行,直到清空 microQueue
多层嵌套 推理需模拟"每次大循环后立即清 micro"
相关推荐
做前端的娜娜子36 分钟前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅44 分钟前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni1 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学2 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端
赵庆明老师3 小时前
Vben精讲:21-详解web-antd:tsconfig.json
前端·json·vim
wc883 小时前
微软EDGE浏览器功能学习
前端·学习·edge
破z晓3 小时前
javascript 导出excel表
开发语言·javascript·excel
Csvn3 小时前
🎯 原生 `<dialog>` 元素:终于可以扔掉一半的自定义弹窗组件了?
前端
Csvn3 小时前
🎨 CSS @layer:用「层叠优先级」终结样式打架的世纪难题
前端