Node.js 事件循环(Event Loop)是 Node.js 运行时环境中的一个重要概念。它负责监听和处理异步事件,使得 Node.js 可以在单线程的情况下实现高并发和非阻塞式的IO操作。Node事件循环如图所示:
具体步骤如下:
1. 加载主模块代码并执行其中同步代码
2. 初始化事件循环,进入事件循环,在循环中不停地监听事件队列
3. 在进入事件循环后首先检查 是否有nextTick和Promise的事件队列。执行清空队列,nextTick优先级高于Promise
4. 进入timer阶段。主要执行setTimeout/setInterval的回调
5. 还有pending callbacks和idle阶段 执行部分的回调
6. 进入Poll阶段,此阶段主要执行文件读取/网络请求监听,这里会有一定的阻塞。详细步骤看图。
7. 进入checks阶段 主要执行setImmediate的回调
8. close backs阶段 例如socket的关闭的回调
我们看看一个简单的示例:
const fs = require("fs");
const path = require("path");
setTimeout(() => console.log("Timer 1 finished"), 0);
setImmediate(() => console.log("Immediate 1 finished"));
fs.readFile(path.resolve(__dirname, "./index.html"), () => {
console.log("I/O finished");
setTimeout(() => console.log("Timer 2 finished"), 0);
setTimeout(() => console.log("Timer 3 finished"), 300);
setImmediate(() => console.log("Immediate 2 finished"));
});
console.log("Hello from the top-level code");
如果你能知道执行顺序的话,说明你有点明白了。
Hello from the top-level code
Timer 1 finished
Immediate 1 finished
I/O finished
Immediate 2 finished
Timer 2 finished
Timer 3 finished
这是一道比较常见的面试题:
async function async1() {
console.log("async1 started");
await async2();
console.log("async end");
}
async function async2() {
console.log("async2");
}
console.log("script start.");
setTimeout(() => {
console.log("setTimeout0");
}, 0);
setTimeout(() => {
console.log("setTimeout3");
}, 3);
setImmediate(() => {
console.log("setImmediate");
});
process.nextTick(() => {
console.log("nextTick");
});
async1();
new Promise((resolve) => {
console.log("promise1");
resolve();
console.log("promise2");
}).then(() => {
console.log("promise.then");
});
console.log("script end.");
按照上述事件循环的步骤, 输出结果为:
script start.
async1 started
async2
promise1
promise2
script end.
nextTick
async end
promise.then
setTimeout0
setImmediate
setTimeout3
这里 setTimeout3和setImmediate的顺序,根据不同电脑顺序有所不同。如果电脑比较好的,应该是我这个结果😄。反之会先打印setTimeout3再打印setImmediate
如果你上面的面试题能独立完成。那么你的Node事件循环应该没有什么问题了。