← MongoDB 删除文档 process.env 环境变量 →

Node.js函数与核心模块速查手册:从fs到worker_threads的系统化接口梳理

著
原创 2026-10-14 Node.js 已有人查阅

速查表的价值在于“可查阅”。按功能域分组、标注同步/异步/流式差异、给出最小可用示例。以下内容按模块划分,每个模块先交代设计意图,再以表格加代码片段的方式呈现核心接口。

一、fs:文件系统操作的接口分层

Node.js的fs模块是API设计的一个典型样本。同一功能通常提供三种形态:回调版、fs/promises版、以及Sync同步版。同步版在启动脚本或CLI工具中方便,但在服务端请求路径上直接调用会阻塞事件循环,这是需要留意的边界。

高频接口速查

接口 说明 形态
fs.readFile 读取整个文件 回调/Promise/Sync
fs.writeFile 写入文件,不存在则创建 同上
fs.appendFile 追加内容 同上
fs.mkdir 创建目录,recursive:true支持嵌套 同上
fs.readdir 读取目录内容 同上
fs.stat 获取文件状态(大小、类型、时间戳) 同上
fs.rename 重命名或移动 同上
fs.unlink 删除文件 同上
fs.rm 删除文件或目录,替代旧的rmdir 同上
fs.createReadStream 创建可读流 流式
fs.createWriteStream 创建可写流 流式
fs.watch 监听文件变化 事件式

fs/promises是现在化用法中的优选,尤其在async/await上下文中。一个容易忽略的差异是:fs/promises的readFile返回Buffer,如果不传编码会得到原始字节,而非字符串。在处理非UTF-8文件时需显式指定encoding。

示例:读取配置文件并捕获特定错误码。

const fs = require('fs/promises');

async function loadConfig(filePath) {
  try {
    const raw = await fs.readFile(filePath, 'utf8');
    return JSON.parse(raw);
  } catch (err) {
    if (err.code === 'ENOENT') {
      throw new Error(`配置文件不存在: ${filePath}`);
    }
    throw err;
  }
}

二、path:跨平台路径处理的确定性工具集

path模块是Node.js中少有的“纯函数”模块——不产生I/O,只做字符串计算。它的核心价值在于抹平POSIX与Windows之间的分隔符差异。开发中经常看到手动拼接dir+'/'+file的写法,这在Windows上会埋下隐患。path.join和path.resolve是两个使用频率最高的接口,但它们的语义有明确区别:join只是拼接并规范化分隔符,resolve则会从右向左解析,直到构造出绝对路径。

接口 行为
path.join(...segments) 用平台分隔符拼接,规范化结果
path.resolve(...segments) 生成绝对路径,从右向左解析
path.basename(p,ext?) 取文件名,可去除扩展名
path.dirname(p) 取目录部分
path.extname(p) 取扩展名(含.)
path.normalize(p) 规范化路径中的..与.
path.relative(from,to) 计算相对路径
path.sep 平台分隔符,POSIX为/,Windows为\

path.resolve的行为需要特别留意:如果参数列表中某一项是绝对路径,前面所有参数会被丢弃。这也是它在处理用户输入时比join更安全的原因之一。

三、http与https:服务端与客户端接口

http模块的接口设计保留了Node.js早期“底层但灵活”的风格。createServer返回http.Server实例,其回调接收IncomingMessage(请求)与ServerResponse(响应)。请求体不会自动解析,需要通过data事件累积或使用流式处理。这是与Express等框架最直观的差异——框架帮你做了body解析,但代价是隐藏了流控细节。

接口 用途
http.createServer([options],handler) 创建HTTP服务
http.request(options[,callback]) 发起HTTP请求
http.get(url[,options][,callback]) request的GET快捷方式
server.listen(port[,host][,backlog][,callback]) 监听端口
server.close([callback]) 停止接收新连接
req.on('data',chunk=>{}) 流式接收请求体
res.writeHead(status,headers) 写入状态码与响应头
res.write(chunk) 写入响应体分片
res.end([data]) 结束响应

一个常见误区:在http.createServer中直接调用res.end()后仍然尝试res.write(),会触发ERR_STREAM_WRITE_AFTER_END。响应流在end()调用后即进入关闭流程,后续写入不再被接受。

四、stream:流式数据处理的四类抽象

Stream是Node.js中抽象层级较高的一组接口,也是理解成本较高的部分。四种基本类型——Readable、Writable、Duplex、Transform——对应了数据流动的不同方向与转换场景。pipeline是处理多级流转时的推荐方式,它会在任意环节出错时统一销毁所有流,避免资源泄漏。

接口 说明
stream.Readable 可读流,数据源
stream.Writable 可写流,数据目标
stream.Duplex 双向流,如TCPsocket
stream.Transform 转换流,读写间做处理
stream.pipeline(...streams,callback) 管道串联,自动错误清理
readable.pipe(dest) 基础管道,不处理错误传播
stream.finished(stream,callback) 监听流结束或出错
stream/promises.pipeline Promise版pipeline

pipe与pipeline的选择:简单场景下pipe够用,但一旦上游出错,下游不会被自动关闭。pipeline解决了这个问题,它在生产环境中更稳妥。

五、crypto:哈希、加密与随机数

crypto模块提供了底层密码学原语。createHash用于单向摘要,createHmac用于带密钥的摘要,randomBytes用于生成密码学安全的随机值。createCipheriv和createDecipheriv需要显式指定算法、密钥和IV,不再使用已废弃的createCipher。

接口 用途
crypto.createHash(algo) 创建哈希对象,update+digest
crypto.createHmac(algo,key) 创建HMAC
crypto.randomBytes(size) 生成安全随机字节
crypto.createCipheriv(algo,key,iv) 对称加密
crypto.createDecipheriv(algo,key,iv) 对称解密
crypto.timingSafeEqual(a,b) 恒定时间比较,防时序攻击

示例:验证webhook签名的恒定时间比较。

const crypto = require('crypto');

function verifySignature(payload, secret, receivedSig) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  const expectedBuf = Buffer.from(expected, 'hex');
  const receivedBuf = Buffer.from(receivedSig, 'hex');
  if (expectedBuf.length !== receivedBuf.length) return false;
  return crypto.timingSafeEqual(expectedBuf, receivedBuf);
}

timingSafeEqual的长度检查是必要的——长度不同时会抛出异常,而不是返回false。

六、child_process与worker_threads:并行执行的两种路径

child_process与worker_threads解决的是不同层面的并行需求。child_process启动的是独立进程,拥有独立的内存空间和V8实例,适合运行外部命令或隔离度要求高的任务。worker_threads则在同一个进程内创建线程,共享部分内存(通过SharedArrayBuffer),线程间通信开销更低,适合CPU密集型计算的拆分。

child_process核心接口

接口 行为
spawn(command[,args][,options]) 启动进程,返回流式接口
exec(command[,options][,callback]) 执行命令,缓冲输出后回调
execFile(file[,args][,options][,callback]) 执行可执行文件,不经过shell
fork(modulePath[,args][,options]) 启动Node子进程,内置IPC通道

worker_threads核心接口

接口 行为
newWorker(filename[,options]) 创建工作线程
worker.postMessage(value) 向工作线程发送消息
parentPort.on('message',handler) 在主线程接收消息
worker.terminate() 强制终止线程
isMainThread 判断当前是否为主线程

exec与execFile的差异在于shell解析:exec会将命令字符串交给shell,支持管道和通配符,但也带来注入风险。execFile直接执行可执行文件,不经过shell,在参数可控的场景下更安全。

七、events与EventEmitter:异步架构的通信基座

EventEmitter是Node.js中许多核心类的基类,包括http.Server、stream.Readable、net.Socket等。它的接口不多,但组合方式灵活。once注册的监听器在首次触发后自动移除,适合一次性初始化完成的通知。removeListener需要传入与原监听器相同的函数引用,匿名函数无法移除——这是实际调试中容易踩的坑。

接口 说明
emitter.on(event,listener) 注册监听器
emitter.once(event,listener) 注册一次性监听器
emitter.emit(event,...args) 触发事件
emitter.off(event,listener) 移除监听器(removeListener别名)
emitter.listenerCount(event) 获取监听器数量
emitter.setMaxListeners(n) 调整监听器数量上限

默认最大监听器数为10。超过时会打印警告,但不会阻止注册。在内存紧张的长驻进程中,大量监听器未及时移除是常见泄漏源。

八、process与全局能力:进程级接口

process是全局对象,无需require。它的接口横跨环境变量、进程控制、性能计时、信号处理等多个维度。process.nextTick与setImmediate的调度层级不同:nextTick在当前操作完成后、事件循环进入下一阶段前执行,setImmediate则在check阶段执行。nextTick的递归调用会耗尽事件循环,需要留意。

接口 说明
process.argv 命令行参数数组
process.env 环境变量对象
process.exit([code]) 同步退出进程
process.nextTick(cb) 当前操作后立即执行
process.hrtime.bigint() 高精度时间,返回BigInt
process.memoryUsage() 内存使用量
process.on('uncaughtException',fn) 未捕获异常兜底
process.on('unhandledRejection',fn) 未处理Promise拒绝兜底

uncaughtException监听器不是错误恢复手段。在异常发生后,进程状态可能已不可靠,正确的做法是在监听器中记录信息后退出,由外部工具重启。

九、本节课程知识要点

速查表的使用方式是“查阅”而非“通读”。建议在编辑器或笔记工具中保留一份按模块索引的版本,遇到接口记忆模糊时快速定位。更重要的是理解各接口的边界:同步接口的阻塞代价、流式接口的错误传播机制、并行方案中进程与线程的取舍。这些判断比记住函数签名更能影响代码质量。

练习思考题

  1. fs.promises.readFile与fs.createReadStream在读取大文件时的内存行为有何差异?什么场景下应当优先选择流式读取?

  2. path.join和path.resolve在传入/foo与bar时分别返回什么?为什么resolve在处理用户上传路径时可能更合适?

  3. pipeline相比pipe在错误处理上做了哪些额外工作?如果不用pipeline,需要手动处理哪些事件?

  4. worker_threads的postMessage传递对象时是结构化克隆还是共享内存?SharedArrayBuffer在什么条件下才能在线程间共享?

← MongoDB 删除文档 process.env 环境变量 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号