🏠 首页 攻略 Event Loop是什么?前端异步编程的幕后导演

Event Loop是什么?前端异步编程的幕后导演

Event Loop(事件循环)是JavaScript处理异步操作的核心机制。理解它,你就理解了为什么setTimeout不一定准时执行、为什么Promise能解决回调地狱。本文用餐厅类比让你彻底搞懂这个概念。

Event Loop 到底是什么?用餐厅来理解

想象你去一家餐厅吃饭。你坐下来点餐,服务员把单子交给厨房。**厨房开始做菜需要时间,但你不会傻坐着干等。**你会先喝口水、看看手机,或者跟朋友聊天。等菜做好了,服务员会通知你。

JavaScript 的 Event Loop 就是这个「不傻等」的机制。

在浏览器里,JavaScript 是单线程的——也就是说,它一次只能做一件事。如果有个操作很慢(比如发网络请求),整个页面就会卡住。Event Loop 的出现,就是为了解决这个问题:让程序能在等待慢操作的同时,继续做其他事。

为什么要懂 Event Loop?

你可能写过这样的代码:

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

你以为是 1-2-3?实际输出是 1-3-2

这就是 Event Loop 在起作用。不理解它,你会被各种"奇怪"的行为搞懵:

  • 为什么 Promise 比 setTimeout 优先执行?
  • 为什么页面会在大量异步操作时卡顿?
  • 为什么有些代码"看起来没问题"却总是出问题?

搞懂 Event Loop,你就拿到了 JavaScript 异步编程的"说明书"。

Event Loop 的工作流程

Event Loop 的工作可以用四个关键词概括:调用栈、任务队列、微任务队列、循环。

第一步:调用栈(Call Stack)

调用栈就像一个待办清单。代码从上到下执行,每遇到一个函数就压入栈顶,执行完就弹出。如果栈满了(函数嵌套太深),浏览器会报"栈溢出"错误。

第二步:任务队列(Task Queue / Macrotask Queue)

当遇到异步操作(比如 setTimeout、文件读取),JavaScript 不会停下等待。它把这件事丢给浏览器内核去处理,自己继续执行后面的代码。异步操作完成后,结果会被放入任务队列排队。

第三步:微任务队列(Microtask Queue)

微任务和宏任务的区别,就像加急件和普通快递。Promise.then、MutationObserver 这些属于微任务,优先级更高。每次调用栈清空后,Event Loop 会先处理完所有微任务,再处理一个宏任务。

第四步:循环

Event Loop 不断重复这个过程:

  1. 执行调用栈里的同步代码
  2. 清空微任务队列
  3. 从任务队列取出一个宏任务执行
  4. 回到第 2 步

就这么循环往复,永不停歇。直到页面关闭。

一道经典面试题

console.log('A');

setTimeout(() => console.log('B'), 0);

Promise.resolve().then(() => console.log('C'));

console.log('D');

输出是什么?

答案是:A → D → C → B

拆解一下:

  • A 和 D 是同步代码,直接执行
  • Promise.then 是微任务,放进微任务队列
  • setTimeout 是宏任务,放进任务队列
  • 同步代码执行完后,先处理微任务(C),再处理宏任务(B)

总结

Event Loop 不是某个框架的专利,它是 JavaScript 引擎内置的机制。理解它不需要你背下所有细节,但要知道三个核心:

  1. JavaScript 是单线程的,靠 Event Loop 实现"异步不阻塞"
  2. 微任务优先于宏任务,Promise 比 setTimeout 更快
  3. Event Loop 永不停止,只要页面开着,它就在循环

下次再遇到异步代码的执行顺序问题,别猜了。想想那个餐厅:厨房在做菜,你在旁边等着——但该你先走的,一口都不会少。