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"
相关推荐
Eshine、36 分钟前
解决前端项目中,浏览器无法正常加载带.gz名称的文件
前端·vue3·.gz·.gz名称的js文件无法被加载
q***38511 小时前
TypeScript 与后端开发Node.js
javascript·typescript·node.js
用户47949283569151 小时前
别再当 AI 的"人肉定位器"了:一个工具让 React 组件秒定位
前端·aigc·ai编程
Nan_Shu_6142 小时前
学习:Sass
javascript·学习·es6
WYiQIU2 小时前
面了一次字节前端岗,我才知道何为“造火箭”的极致!
前端·javascript·vue.js·react.js·面试
qq_316837752 小时前
uniapp 观察列表每个元素的曝光时间
前端·javascript·uni-app
小夏同学呀2 小时前
在 Vue 2 中实现 “点击下载条码 → 打开新窗口预览 → 自动唤起浏览器打印” 的功能
前端·javascript·vue.js
芳草萋萋鹦鹉洲哦2 小时前
【vue】导航栏变动后刷新router的几种方法
前端·javascript·vue.js
zero13_小葵司2 小时前
JavaScript性能优化系列(八)弱网环境体验优化 - 8.3 数据预加载与缓存:提前缓存关键数据
javascript·缓存·性能优化
1***y1782 小时前
Vue项目性能优化案例
前端·vue.js·性能优化