事件循环 (Event Loop)
1. 事件循环 (Event Loop)
事件循环是 JavaScript 处理异步操作的核心机制。它允许单线程的 JavaScript 执行非阻塞的 I/O 操作。
宏任务 vs. 微任务
-
宏任务: 由浏览器/Node.js 环境发起的任务。例如:
-
setTimeout,setInterval -
setImmediate(Node.js 特有) -
I/O 操作 (如读取文件、网络请求)
-
UI 渲染 (浏览器)
-
整体的
script代码本身
-
-
微任务: 由 JavaScript 自身发起的任务,通常与“承诺”相关。例如:
-
Promise.then(),Promise.catch(),Promise.finally() -
process.nextTick(Node.js 特有,优先级最高) -
MutationObserver(浏览器)
-
执行规则 (浏览器)
-
执行一个宏任务(通常是最老的或最先入队的),例如执行全局的脚本。
-
执行过程中遇到微任务,就将其放入微任务队列;遇到宏任务,就将其放入宏任务队列。
-
当前宏任务执行完毕后,立即清空整个微任务队列(执行所有微任务)。
-
进行 UI 渲染(如果需要)。
-
从宏任务队列中取出下一个宏任务,开始新一轮的循环。
核心:一个宏任务 → 所有微任务 → (渲染) → 下一个宏任务。
Node.js 与浏览器的差异
Node.js 的事件循环基于 libuv 库,其阶段划分比浏览器更复杂。
Node.js 事件循环阶段 (简化版):
-
Timers: 执行
setTimeout和setInterval的回调。 -
Pending callbacks: 执行延迟到下一个循环的 I/O 回调。
-
Idle, Prepare: 内部使用。
-
Poll: 检索新的 I/O 事件;执行 I/O 相关的回调(如读取文件)。必要时会在此阶段阻塞。
-
Check: 执行
setImmediate的回调。 -
Close callbacks: 执行关闭事件的回调(如
socket.on('close', ...))。
process.nextTick() 在一个阶段结束后、下一个阶段开始前执行,它拥有一个独立的队列,优先级高于微任务。
主要差异总结:
| 特性 | 浏览器 | Node.js |
|---|---|---|
| 阶段 | 相对简单(宏任务、微任务、渲染) | 分为多个明确阶段(Timers, Poll, Check等) |
setImmediate |
不支持 | 支持,在 Check 阶段执行 |
process.nextTick |
不支持 | 支持,优先级最高(在各阶段间执行) |
| 微任务执行时机 | 在每个宏任务之后 | 在事件循环的每个阶段之后 |
复杂异步代码执行顺序示例
console.log('1. Script Start'); // 同步代码,宏任务1开始
let a;
let b = new Promise(resolve=>{
console.log(12)
setTimeout(()=>{
resolve();
}, 1000)
})
a= new Promise(resolve=>{
console.log(a)
b.then(()=>{
console.log(a)
console.log(13)
a.then(()=>{ // 没有resolve,后面不执行
resolve(true)
console.log(14)
})
})
})
Promise.resolve()
.then(() => {
console.log('7. Promise 11'); // 微任务
return Promise.resolve(10) // return Promise.resolve().then(() => {return 10 }) 相当于增加了两次空的微任务
}).then((a) => {
console.log(a + '. Promise 12'); // 微任务
})
.then(() => {
console.log('8. Promise 21'); // 微任务
});
setTimeout(() => {
console.log('2. setTimeout'); // 回调是宏任务
Promise.resolve().then(() => {
console.log('3. Promise inside setTimeout'); // 微任务
});
}, 0);
Promise.resolve()
.then(() => {
console.log('4. Promise 1'); // 微任务
})
.then(() => {
console.log('5. Promise 2'); // 微任务
})
.then(() => {
console.log('9. Promise 3'); // 微任务
})
.then(() => {
console.log('10. Promise 4'); // 微任务
});
console.log('6. Script End'); // 同步代码,宏任务1结束
// 预期输出顺序:
// 1. Script Start
// 12
// undefined
// 6. Script End
// 7. Promise 11
// 4. Promise 1
// 5. Promise 2
// 9. Promise 3
// 10. Promise 12
// 10. Promise 4
// 8. Promise 21
//
// 2. setTimeout
// 3. Promise inside setTimeout
// Promise{<pending>}
// 13

浙公网安备 33010602011771号