Skip to content

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 的核心模块提供了丰富的功能,涵盖了从二进制数据处理到网络编程的各个方面:

  1. Buffer:高效处理二进制数据
  2. Stream:流式数据处理,支持背压机制
  3. fs:文件系统操作,支持同步、异步和流式操作
  4. process/child_process/cluster:进程管理
  5. net/http:网络编程

理解这些核心模块的底层机制和使用方法,能够帮助我们编写出更加高效和稳定的 Node.js 应用程序。在实际开发中,合理使用这些模块可以显著提升应用的性能和可维护性。