nodejs 事件循环是一个典型的生产者/消费者模型,异步 I/O、网络请求等是事件的生产者,源源不断为 Node 提供不同类型的事件,这些事件被传递到对应的观察者那里,事件循环则从观察者那里取出事件并处理。
事件循环、观察者、请求对象、I/O 线程池共同构成了 Node 异步 I/O 模型的基本要素。
Node 异步 I/O 几个关键词:单线程、事件循环、观察者、I/O 线程池,JavaScript 是单线程,node自身是多线程,只是 I/O 线程使用的 CPU 较少。除了用户代码无法并行执行外,所有的 I/O(磁盘 I/O 和网络 I/O 等)是可以并行起来的。
node 中还存在一些与 I/O 无关的异步 API,setTimeout()、setInteval()、setImmediate()、process.nextTick()
process.nextTick()=> idle 观察者
setImmediate() => check 观察者
事件循环对观察者的检查有先后顺序,idle观察者先于 I/O 观察者,I/O 观察者先于 check 观察者。
const fs = require("fs");
const path = require("path");
const wait = () =>
new Promise((resolove, reject) => {
setTimeout(resolove(true), 3);
});
fs.readFile(
path.resolve(__dirname, "./limit.js"),
"utf-8",
async (err, data) => {
console.log("读取的文件内容1");
}
);
fs.readFile(
path.resolve(__dirname, "./limit.js"),
"utf-8",
async (err, data) => {
console.log("读取的文件内容2");
await wait();
console.log("读取文件内容2,等待3 秒后输出");
process.nextTick(() => {
console.log("读取文件内容2,等待3 秒后执行 process.nextTick");
});
}
);
console.log("start");
setTimeout(function () {
console.log("setTimeout-1");
process.nextTick(function () {
console.log("setTimeout-1-process.nextTick");
});
new Promise(function (resolve) {
console.log("setTimeout-1-Promise");
resolve();
}).then(function () {
console.log("setTimeout-1-Promise-then");
});
});
setImmediate(() => {
console.log("setImmediate-1");
process.nextTick(function () {
console.log("setImmediate-1-process.nextTick-1");
});
});
setImmediate(() => {
console.log("setImmediate-2");
});
process.nextTick(function () {
console.log("process.nextTick-1");
});
process.nextTick(function () {
console.log("process.nextTick-2");
});
new Promise(function (resolve) {
console.log("Promise-1");
resolve();
}).then(function () {
console.log("Promise-1-then");
});
setTimeout(function () {
console.log("setTimeout-2");
process.nextTick(function () {
console.log("setTimeout-2-process.nextTick");
});
new Promise(function (resolve) {
console.log("setTimeout-2-Promise");
resolve();
}).then(function () {
console.log("setTimeout-2-Promise-then");
});
});
// 执行结果
// start
// Promise-1
// 在每轮循环中,会将 process.nextTick 全部执行完,优先级> promise.then
// process.nextTick-1
// process.nextTick-2
// Promise-1-then
// setTimeout timer 优先级> setImmediate check 观察者
// setTimeout-1
// setTimeout-1-Promise
// setTimeout-1-process.nextTick
// setTimeout-1-Promise-then
// setTimeout-2
// setTimeout-2-Promise
// setTimeout-2-process.nextTick
// setTimeout-2-Promise-then
// 一次循环只执行一个 setImmediate
// setImmediate-1
// setImmediate-1-process.nextTick-1
// setImmediate-2
// 读取的文件内容1
// 读取的文件内容2
// 读取文件内容2,等待3 秒后输出
// 读取文件内容2,等待3 秒后执行 process.nextTick