在 JavaScript 中,Event Loop(事件循环) 是一种运行机制,用来协调代码执行、事件处理以及异步任务(如 setTimeout、Promise、async/await)。它的核心作用是保证 非阻塞 的执行方式,使得 JS 虽然是单线程,却能同时处理同步和异步操作。
基本原理
- 调用栈(Call Stack):JS 中用于保存正在执行的函数。只有栈清空之后,事件循环才会去检查异步任务。
- 任务队列(Task Queue):异步任务完成后,会把回调函数放置在任务队列,等待执行。
- 事件循环(Event Loop):不断检查调用栈是否为空,如果为空,就把任务队列中的第一个任务推入调用栈中执行。
宏任务与微任务
事件循环中,任务又分两类:
- 宏任务(MacroTask):整体的执行块,如
setTimeout、setInterval、setImmediate、I/O、script 整体代码等。 - 微任务(MicroTask):更细粒度的回调,例如
Promise.then、process.nextTick、queueMicrotask。
事件循环的执行顺序通常是:
- 执行一个宏任务(比如整段
script)。 - 宏任务执行完毕后,清空所有微任务队列。
- 开始下一个宏任务。
执行流程举例
jsconsole.log('1');
setTimeout(() => {
console.log('2');
}, 0);
Promise.resolve().then(() => {
console.log('3');
});
console.log('4');
执行过程:
console.log('1')→ 输出 1。setTimeout回调(宏任务) → 加入宏任务队列。Promise.then(微任务) → 加入微任务队列。console.log('4')→ 输出 4。- 清空微任务队列:输出 3。
- 开始下一个宏任务:输出 2。
最终输出顺序: 1 → 4 → 3 → 2
JS Event Loop 流程图解
┌───────────────────┐
│ 调用栈 (Call Stack) │
└───────▲───────────┘
│ (执行中函数)
│
┌────────────┴────────────┐
│ │
┌────┴────┐ ┌─────┴─────┐
│ 宏任务队列 │ │ 微任务队列 │
│ (Macrotask)│ │ (Microtask)│
│ setTimeout│ │ Promise.then│
│ setInterval│ │ queueMicrotask│
│ script整体 │ │ process.nextTick│
└────┬────┘ └─────┬─────┘
│ │
└───────────┬─────────────┘
│
┌─────▼─────┐
│ Event Loop│
└─────▲─────┘
│ 不断检查:
│ 1. 栈是否为空?
│ 2. 微任务队列是否需要清空?
│ 3. 再取宏任务进入栈执行。
文章评论