JavaScript 运行在单线程上,因此一次只能执行一个操作。事件循环让它能够处理异步工作而不阻塞:它运行调用栈,当栈为空时,从队列中拉取回调。
有两个队列具有不同的优先级:
- 微任务:Promise 回调(
.then)、queueMicrotask。在每个任务后完全清空,在渲染前。 - 宏任务:
setTimeout、I/O、UI 事件。每个循环迭代处理一个。
js
console.log("1"); // sync
setTimeout(() => console.log(), );
.().( .());
.();
为什么这很重要
- 同步代码首先运行:
1、4。 - 栈清空 → 清空所有微任务:
3。 - 然后执行一个宏任务:
2。
这就是为什么 Promise.then 总是在 setTimeout(…, 0) 之前运行,即使两者都是「异步」——微任务有优先级。
一个实际的后果
js
// ❌ blocks the single thread — UI freezes for 5 seconds
while (Date.now() - start < 5000) {}
长同步工作会阻塞所有内容(渲染、点击)。将重型 CPU 工作卸载到 Web Worker(一个真正的独立线程)。
为什么这很重要
理解事件循环解释了异步顺序、为什么 Promise 在定时器之前解决,以及为什么永远不要阻塞主线程——这是所有异步 JavaScript 的核心心智模型。
