第 4 章:核心模块实战
Node 自带一套精悍的核心模块,
fs、path、http、stream是日常开发四大件。这一章用真实代码讲清它们的用法。
4.1 fs:文件系统
所有文件操作都在 fs 模块里。它同时提供回调版、Promise 版、同步版三套 API:
javascript
const fs = require('fs'); // 回调版
const fsp = require('fs/promises'); // Promise 版(推荐)
// 同步版:会阻塞主线程,只用于启动时加载配置
const config = fs.readFileSync('config.json', 'utf8');
// Promise 版:日常开发首选
await fsp.readFile('data.txt', 'utf8'); // 读
await fsp.writeFile('data.txt', '内容'); // 写(覆盖)
await fsp.appendFile('log.txt', '一条日志\n'); // 追加
await fsp.mkdir('dir/sub', { recursive: true }); // 建目录(recursive 自动建父级)
await fsp.rm('dir', { recursive: true, force: true }); // 删除(force 忽略不存在)选择原则:能用 fs/promises 就用它(配合 async/await);readFileSync 这类同步方法只用在启动初始化阶段。
4.2 path:路径处理
跨平台路径处理用 path,不要手拼字符串(Windows 用 \,Linux 用 /):
javascript
const path = require('path');
path.join('src', 'utils', 'tool.js'); // src/utils/tool.js(自动加分隔符)
path.resolve('src', 'tool.js'); // 转成绝对路径
path.dirname('/a/b/c.js'); // /a/b
path.basename('/a/b/c.js'); // c.js
path.extname('/a/b/c.js'); // .js
path.parse('/a/b/c.js'); // { dir, base, ext, name } 拆解技巧:
path.join(__dirname, 'data.json')是基于「当前文件所在目录」定位资源,这是最稳的相对路径写法。
4.3 http:起一个服务器
用原生 http 模块起服务,理解底层原理:
javascript
const http = require('http');
const server = http.createServer((req, res) => {
// req 请求对象,res 响应对象
const { method, url } = req;
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ method, url }));
});
server.listen(3000, () => {
console.log('服务已启动 http://localhost:3000');
});浏览器 ──HTTP请求──► Node http server ──► 你的回调 (req, res)
▲ │
└────────────HTTP响应 ◄──── res.end(内容) ◄─────┘核心概念:
req:请求,含method(GET/POST)、url、headers,POST 的 body 要手动接收;res:响应,writeHead设状态码/头,end发送内容并结束。
4.4 stream:流式处理
流是 Node 最强大的特性之一,用来边读边处理大数据,而不是一次性全部载入内存:
【一次性读取】1GB 文件 ──► 全部读进内存 ──► 处理(内存爆了)
【流式读取】 1GB 文件 ──► 一块一块流进来 ──► 边读边处理(内存恒定)四种流:
| 类型 | 作用 | 例子 |
|---|---|---|
| Readable | 可读流 | fs.createReadStream |
| Writable | 可写流 | fs.createWriteStream |
| Duplex | 双工流 | net.Socket |
| Transform | 转换流 | zlib.createGzip |
管道(pipe)串联——文件复制、压缩、转发,一条管道搞定:
javascript
const fs = require('fs');
const zlib = require('zlib');
// 读文件 → gzip 压缩 → 写文件
fs.createReadStream('big.log')
.pipe(zlib.createGzip()) // 转换流:压缩
.pipe(fs.createWriteStream('big.log.gz'));可读流 ──pipe──► 转换流 ──pipe──► 可写流
(读文件) │ (压缩/加密) │ (写文件)
└────── 数据块流动 ──────┘事件监听(不 pipe 时手动处理):
javascript
const rs = fs.createReadStream('big.log', { encoding: 'utf8' });
rs.on('data', chunk => console.log('一块', chunk.length));
rs.on('end', () => console.log('读完了'));
rs.on('error', err => console.error('出错', err));实战意义:处理大文件、转发请求/响应、上传下载、对接大模型的流式输出,全都靠 stream。第 6 章会看到流式接收大模型响应的完整应用。
4.5 本章小结
| 模块 | 用途 | 要点 |
|---|---|---|
| fs | 文件读写 | 优先 fs/promises,同步版只用于启动初始化 |
| path | 路径处理 | path.join 跨平台,__dirname 定位资源 |
| http | HTTP 服务 | createServer + (req, res),理解请求响应模型 |
| stream | 流式处理 | 边读边处理,pipe 管道串联,是大数据/流式输出基石 |
下一章预告
原生 http 写路由太繁琐,实战都会上框架。Express 的中间件「洋葱模型」是怎么回事?Koa 又有什么不同?