Node.js 核心模块与底层机制
Node.js 提供了丰富的核心模块,这些模块封装了底层操作系统的功能,使得开发者能够轻松地进行文件操作、网络编程、进程管理等任务。理解这些核心模块的机制对于深入掌握 Node.js 至关重要。
一、Buffer 模块:处理二进制数据
Buffer 是 Node.js 用来处理二进制数据的核心模块,它允许我们在 JavaScript 中直接操作字节。
1. Buffer 基础使用
javascript
// 创建 Buffer 的不同方式
// 1. 分配指定大小的 Buffer(不安全,可能包含旧数据)
const buf1 = Buffer.allocUnsafe(10);
console.log(buf1); // <Buffer 00 00 00 00 00 00 00 00 00 00>
// 2. 分配并初始化为 0 的 Buffer(安全)
const buf2 = Buffer.alloc(10);
console.log(buf2); // <Buffer 00 00 00 00 00 00 00 00 00 00>
// 3. 从数组创建 Buffer
const buf3 = Buffer.from([1, 2, 3, 4, 5]);
console.log(buf3); // <Buffer 01 02 03 04 05>
// 4. 从字符串创建 Buffer
const buf4 = Buffer.from('Hello World', 'utf8');
console.log(buf4); // <Buffer 48 65 6c 6c 6f 20 57 6f 72 6c 64>
// 5. 从 ArrayBuffer 创建 Buffer
const arrayBuffer = new ArrayBuffer(16);
const buf5 = Buffer.from(arrayBuffer);
console.log(buf5); // <Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00>2. Buffer 操作
javascript
// Buffer 基本操作
const buf = Buffer.from('Hello World');
// 读取数据
console.log(buf.length); // 11
console.log(buf.toString()); // 'Hello World'
console.log(buf.toString('hex')); // '48656c6c6f20576f726c64'
// 写入数据
buf.write('Hi'); // 从位置 0 开始写入
console.log(buf.toString()); // 'Hiello World'
// 复制 Buffer
const buf1 = Buffer.from('Hello');
const buf2 = Buffer.alloc(10);
buf1.copy(buf2);
console.log(buf2.toString()); // 'Hello'
// 切片操作
const buf3 = Buffer.from('Hello World');
const slice = buf3.slice(0, 5);
console.log(slice.toString()); // 'Hello'
// 比较 Buffer
const bufA = Buffer.from('A');
const bufB = Buffer.from('B');
console.log(bufA.compare(bufB)); // -1 (A < B)3. Buffer 性能优化
javascript
// Buffer 池化优化
const bufferPool = [];
const BUFFER_SIZE = 1024;
function getBuffer(size) {
// 从池中获取 Buffer
if (size <= BUFFER_SIZE && bufferPool.length > 0) {
return bufferPool.pop();
}
return Buffer.allocUnsafe(size);
}
function releaseBuffer(buf) {
// 将 Buffer 放回池中
if (buf.length <= BUFFER_SIZE) {
bufferPool.push(buf);
}
}
// 使用示例
const buf = getBuffer(512);
buf.write('Hello World');
console.log(buf.toString());
releaseBuffer(buf);二、Stream 模块:流式数据处理
Stream 是 Node.js 中处理流式数据的核心模块,它允许我们以流的方式处理数据,而不是一次性加载所有数据到内存中。
1. 可读流(Readable Stream)
javascript
const { Readable } = require('stream');
// 创建自定义可读流
class NumberStream extends Readable {
constructor(options) {
super(options);
this.current = 0;
this.max = options.max || 10;
}
_read() {
if (this.current < this.max) {
const number = this.current++;
this.push(number.toString());
this.push('\n');
} else {
this.push(null); // 结束流
}
}
}
// 使用自定义可读流
const numberStream = new NumberStream({ max: 5 });
numberStream.on('data', (chunk) => {
console.log('接收到数据:', chunk.toString());
});
numberStream.on('end', () => {
console.log('流结束');
});2. 可写流(Writable Stream)
javascript
const { Writable } = require('stream');
const fs = require('fs');
// 创建自定义可写流
class UpperCaseStream extends Writable {
constructor(options) {
super(options);
}
_write(chunk, encoding, callback) {
// 将数据转换为大写并输出
console.log(chunk.toString().toUpperCase());
callback(); // 表示写入完成
}
}
// 使用自定义可写流
const upperCaseStream = new UpperCaseStream();
upperCaseStream.write('hello');
upperCaseStream.write('world');
upperCaseStream.end();
// 管道操作
const readable = fs.createReadStream('input.txt');
const writable = fs.createWriteStream('output.txt');
readable.pipe(writable);3. 双工流(Duplex Stream)
javascript
const { Duplex } = require('stream');
// 创建双工流
class EchoStream extends Duplex {
constructor(options) {
super(options);
this.buffer = [];
}
_write(chunk, encoding, callback) {
// 将写入的数据存储到缓冲区
this.buffer.push(chunk);
callback();
}
_read() {
// 从缓冲区读取数据
if (this.buffer.length > 0) {
this.push(this.buffer.shift());
} else {
this.push(null); // 没有更多数据
}
}
}
// 使用双工流
const echoStream = new EchoStream();
echoStream.write('Hello');
echoStream.write('World');
echoStream.on('data', (chunk) => {
console.log('Echo:', chunk.toString());
});4. 转换流(Transform Stream)
javascript
const { Transform } = require('stream');
// 创建转换流
class UpperCaseTransform extends Transform {
constructor(options) {
super(options);
}
_transform(chunk, encoding, callback) {
// 转换数据为大写
const upperCaseChunk = chunk.toString().toUpperCase();
callback(null, upperCaseChunk);
}
}
// 使用转换流
const upperCaseTransform = new UpperCaseTransform();
upperCaseTransform.on('data', (chunk) => {
console.log('转换后:', chunk.toString());
});
upperCaseTransform.write('hello');
upperCaseTransform.write('world');
upperCaseTransform.end();5. 流的背压(Backpressure)机制
javascript
const { Readable, Writable } = require('stream');
// 模拟慢速可写流
class SlowWritable extends Writable {
_write(chunk, encoding, callback) {
console.log('写入:', chunk.toString());
// 模拟慢速写入
setTimeout(() => {
callback();
}, 1000);
}
}
// 模拟快速可读流
class FastReadable extends Readable {
constructor(options) {
super(options);
this.current = 0;
}
_read() {
if (this.current < 10) {
const data = `数据${this.current++}\n`;
this.push(data);
} else {
this.push(null);
}
}
}
// 背压处理
const fastReadable = new FastReadable();
const slowWritable = new SlowWritable();
// 使用 pipe 自动处理背压
fastReadable.pipe(slowWritable);
// 手动处理背压
// fastReadable.on('data', (chunk) => {
// if (!slowWritable.write(chunk)) {
// // 如果写入返回 false,暂停读取
// fastReadable.pause();
// }
// });
//
// slowWritable.on('drain', () => {
// // 当可写流准备好接收更多数据时,恢复读取
// fastReadable.resume();
// });三、文件系统(fs)模块
fs 模块提供了文件系统操作的 API,包括文件读写、目录操作等。
1. 同步、异步和 Promise 方式
javascript
const fs = require('fs');
const { promisify } = require('util');
// 1. 同步操作
try {
const data = fs.readFileSync('file.txt', 'utf8');
console.log('同步读取:', data);
} catch (err) {
console.error('同步读取错误:', err);
}
// 2. 异步操作
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) {
console.error('异步读取错误:', err);
return;
}
console.log('异步读取:', data);
});
// 3. Promise 方式
const readFilePromise = promisify(fs.readFile);
readFilePromise('file.txt', 'utf8')
.then(data => {
console.log('Promise 读取:', data);
})
.catch(err => {
console.error('Promise 读取错误:', err);
});
// 4. 使用 fs.promises
fs.promises.readFile('file.txt', 'utf8')
.then(data => {
console.log('fs.promises 读取:', data);
})
.catch(err => {
console.error('fs.promises 读取错误:', err);
});2. 流式文件操作
javascript
const fs = require('fs');
// 流式读取大文件
const readStream = fs.createReadStream('large-file.txt');
const writeStream = fs.createWriteStream('output.txt');
readStream.on('data', (chunk) => {
console.log(`读取到 ${chunk.length} 字节`);
});
readStream.on('end', () => {
console.log('文件读取完成');
});
readStream.on('error', (err) => {
console.error('读取错误:', err);
});
// 管道操作
readStream.pipe(writeStream);
// 监听写入完成
writeStream.on('finish', () => {
console.log('文件写入完成');
});3. 文件监控
javascript
const fs = require('fs');
// 监控文件变化
const watcher = fs.watch('target.txt', (eventType, filename) => {
console.log(`文件 ${filename} 发生了 ${eventType} 事件`);
});
// 停止监控
setTimeout(() => {
watcher.close();
console.log('停止文件监控');
}, 10000);四、进程管理模块
Node.js 提供了多个模块来管理进程和子进程。
1. process 对象
javascript
// process 对象包含当前进程的信息
console.log('进程 ID:', process.pid);
console.log('Node.js 版本:', process.version);
console.log('平台:', process.platform);
console.log('架构:', process.arch);
console.log('当前工作目录:', process.cwd());
console.log('环境变量:', process.env);
// 进程事件
process.on('exit', (code) => {
console.log(`进程即将退出,退出码: ${code}`);
});
process.on('uncaughtException', (err) => {
console.error('未捕获的异常:', err);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
console.error('未处理的 Promise 拒绝:', reason);
process.exit(1);
});
// 内存使用情况
console.log('内存使用情况:', process.memoryUsage());
// CPU 使用情况
console.log('CPU 使用情况:', process.cpuUsage());2. child_process 模块
javascript
const { spawn, exec, execFile, fork } = require('child_process');
// 1. spawn - 启动新进程
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`子进程退出,退出码 ${code}`);
});
// 2. exec - 执行命令
exec('ls -lh /usr', (error, stdout, stderr) => {
if (error) {
console.error(`执行错误: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
console.error(`stderr: ${stderr}`);
});
// 3. fork - 创建 Node.js 子进程
const child = fork('./child.js');
child.on('message', (message) => {
console.log('来自主进程的消息:', message);
});
child.send({ hello: 'world' });3. cluster 模块
javascript
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`主进程 ${process.pid} 正在运行`);
// 衍生工作进程
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 已退出`);
});
} else {
// 工作进程可以共享任何 TCP 连接
// 在本例中,它是一个 HTTP 服务器
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello World\n');
}).listen(8000);
console.log(`工作进程 ${process.pid} 已启动`);
}五、网络模块
Node.js 提供了强大的网络编程能力。
1. net 模块(TCP)
javascript
const net = require('net');
// 创建 TCP 服务器
const server = net.createServer((socket) => {
console.log('客户端已连接');
socket.on('data', (data) => {
console.log('接收到数据:', data.toString());
socket.write('Echo: ' + data);
});
socket.on('end', () => {
console.log('客户端断开连接');
});
socket.write('欢迎连接到服务器!\n');
});
server.listen(8124, () => {
console.log('服务器正在监听端口 8124');
});
// 创建 TCP 客户端
const client = net.createConnection({ port: 8124 }, () => {
console.log('已连接到服务器');
client.write('Hello Server!\n');
});
client.on('data', (data) => {
console.log('服务器响应:', data.toString());
client.end();
});
client.on('end', () => {
console.log('与服务器断开连接');
});2. http 模块
javascript
const http = require('http');
const url = require('url');
// 创建 HTTP 服务器
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const queryString = parsedUrl.query;
console.log(`请求路径: ${path}`);
console.log(`查询参数:`, queryString);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
});
server.listen(3000, () => {
console.log('服务器正在监听端口 3000');
});
// 创建 HTTP 客户端
const options = {
hostname: 'localhost',
port: 3000,
path: '/',
method: 'GET'
};
const req = http.request(options, (res) => {
console.log(`状态码: ${res.statusCode}`);
res.on('data', (chunk) => {
console.log(`响应体: ${chunk}`);
});
});
req.on('error', (e) => {
console.error(`请求遇到问题: ${e.message}`);
});
req.end();六、总结
Node.js 的核心模块提供了丰富的功能,涵盖了从二进制数据处理到网络编程的各个方面:
- Buffer:高效处理二进制数据
- Stream:流式数据处理,支持背压机制
- fs:文件系统操作,支持同步、异步和流式操作
- process/child_process/cluster:进程管理
- net/http:网络编程
理解这些核心模块的底层机制和使用方法,能够帮助我们编写出更加高效和稳定的 Node.js 应用程序。在实际开发中,合理使用这些模块可以显著提升应用的性能和可维护性。