辅助模块速览
本教程共 76 篇 · 第 25 篇 · 更新于 2026-07-25 · 约 6 分钟阅读
25. 辅助模块速览
本节目标:os、util、timers、AbortController、assert 等辅助模块速览。
Node.js 内置了很多小而精的模块,单个拿出来不够写一整章,但日常开发里经常要用到。本章把 os、util、timers、AbortController、assert 五个模块快速过一遍,给你一张实用的速查表。
25.1 os:操作系统信息
os 模块让你读取系统级别的硬件和平台信息,写诊断工具、资源监控、跨平台适配时很有用。
import os from 'node:os';
// 平台与架构
os.platform(); // win32 / linux / darwin
os.arch(); // x64 / arm64
os.release(); // 内核版本
// CPU
const cpus = os.cpus();
console.log(cpus.length); // 逻辑核心数
console.log(cpus[0].model); // CPU 型号
console.log(cpus[0].speed); // 频率(MHz)
// 内存(字节)
os.totalmem(); // 总内存
os.freemem(); // 空闲内存
// 目录
os.homedir(); // 用户主目录
os.tmpdir(); // 系统临时目录
os.hostname(); // 主机名
// 换行符
os.EOL; // Windows 是 \r\n,POSIX 是 \n
一个常见用途是根据 CPU 核心数决定工作线程数量:
import os from 'node:os';
const WORKERS = os.cpus().length;
console.log(`启动 ${WORKERS} 个 worker`);
25.2 util:工具函数
util 模块是 Node.js 的「瑞士军刀」,里面有不少实用工具。
promisify:回调转 Promise
早期 Node 核心模块都是回调风格,util.promisify 可以把它们包装成返回 Promise 的函数:
import { promisify } from 'node:util';
import { exec } from 'node:child_process';
const execAsync = promisify(exec);
const { stdout } = await execAsync('node --version');
console.log(stdout.trim());
现在大部分核心模块都有了 fs/promises 这样的原生 Promise 版本,promisify 主要用来处理一些还没跟进的老接口,或者第三方回调风格库。
inspect:对象深度字符串化
import { inspect } from 'node:util';
const obj = { a: { b: { c: { d: 1 } } } };
console.log(inspect(obj, { depth: 2, colors: true }));
// { a: { b: { c: [Object] } } }
depth 控制展开层级,colors 给类型上色,showHidden 显示不可枚举属性。console.dir 底层调的就是它。
format:格式化字符串
import { format } from 'node:util';
const msg = format('Hello %s, you have %d messages', 'Alice', 3);
// Hello Alice, you have 3 messages
占位符规则:%s 字符串、%d 数字、%j JSON、%o 对象展开。console.log 内部也是先 format 再输出。
types:类型检测
import { types } from 'node:util';
types.isPromise(Promise.resolve()); // true
types.isAsyncFunction(async () => {}); // true
types.isDate(new Date()); // true
types.isRegExp(/abc/); // true
比 typeof 和 instanceof 更精确,尤其在跨 Realm(如 VM 模块创建的上下文)时更可靠。
parseArgs:命令行参数解析
v18.3+ 内置的命令行解析器,不需要装 minimist 或 yargs:
import { parseArgs } from 'node:util';
const { values, positionals } = parseArgs({
options: {
port: { type: 'string', short: 'p', default: '3000' },
verbose: { type: 'boolean', short: 'v' }
},
allowPositionals: true
});
console.log(values.port); // '8080'
console.log(values.verbose); // true
console.log(positionals); // ['start']
// 调用: node app.js -p 8080 -v start
功能不算最丰富,但标准库内置、零依赖,对付一般脚本够用了。
25.3 timers:定时器与 Promise 版
setTimeout、setInterval、setImmediate 在全局就能用,但 timers/promises(v15+)提供了更现代的接口:
import { setTimeout } from 'node:timers/promises';
// 等待 1 秒
await setTimeout(1000);
// 等待并返回一个值
const result = await setTimeout(1000, 'done');
console.log(result); // 'done'
setInterval 的 Promise 版返回异步迭代器:
import { setInterval } from 'node:timers/promises';
const ac = new AbortController();
// 每 500ms 触发一次,最多 5 次
let count = 0;
for await (const startTime of setInterval(500, Date.now(), { signal: ac.signal })) {
console.log('tick', count);
if (++count >= 5) ac.abort();
}
结合 AbortController 可以优雅地停止定时器,不需要记 clearInterval 的句柄。
25.4 AbortController:取消异步操作
AbortController 最早来自 Web 标准,Node.js v15+ 把它引入了服务器端。核心是一个 signal 对象,传给支持它的 API,需要取消时调用 abort()。
取消 fetch 请求
const ac = new AbortController();
// 5 秒后超时
setTimeout(() => ac.abort(), 5000);
try {
const res = await fetch('https://slow.api.com/data', {
signal: ac.signal
});
const data = await res.json();
} catch (err) {
if (err.name === 'AbortError') {
console.log('请求被取消');
}
}
取消 readline 提问
import { createInterface } from 'node:readline/promises';
import { stdin, stdout } from 'node:process';
const ac = new AbortController();
const rl = createInterface({ input: stdin, output: stdout });
// 10 秒没回答就放弃
setTimeout(() => ac.abort(), 10000);
try {
const answer = await rl.question('确认删除吗 (yes/no): ', {
signal: ac.signal
});
} catch (err) {
if (err.name === 'AbortError') {
console.log('操作超时,已取消');
}
} finally {
rl.close();
}
取消流操作
import { createReadStream } from 'node:fs';
const ac = new AbortController();
const stream = createReadStream('big.log', { signal: ac.signal });
ac.abort(); // 立即关闭流
越来越多的 Node.js API 支持 AbortSignal,包括 fs、HTTP 请求、子进程等。它的好处是统一的取消语义——一个 AbortController 可以同时取消多个关联操作。
25.5 assert:断言
assert 模块提供轻量级的断言测试,适合写内联检查或小型测试脚本。重度测试还是推荐内置 Test Runner 或 Jest。
import assert from 'node:assert';
assert.strictEqual(1 + 1, 2);
assert.deepStrictEqual({ a: 1 }, { a: 1 });
// 期望抛出错误
assert.throws(() => {
JSON.parse('invalid');
}, SyntaxError);
// 异步错误
await assert.rejects(async () => {
await fetch('http://invalid.url');
});
建议导入时带上 .strict,避免隐式类型转换的坑:
import assert from 'node:assert/strict';
assert.equal('1', 1); // 严格模式下抛错
25.6 实战:系统资源监控脚本
把几个模块串起来,写一个打印系统状态的脚本:
import os from 'node:os';
import { format } from 'node:util';
function formatBytes(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return format('%s %s', (bytes / Math.pow(k, i)).toFixed(2), sizes[i]);
}
function printStatus() {
const totalMem = os.totalmem();
const freeMem = os.freemem();
const usedMem = totalMem - freeMem;
const cpus = os.cpus();
console.log('=== 系统状态 ===');
console.log(`平台: ${os.type()} ${os.platform()} ${os.arch()}`);
console.log(`主机: ${os.hostname()}`);
console.log(`Node: ${process.version}`);
console.log(`CPU: ${cpus[0].model} x ${cpus.length}`);
console.log(`内存: ${formatBytes(usedMem)} / ${formatBytes(totalMem)}`);
console.log(`负载: ${os.loadavg().map(v => v.toFixed(2)).join(', ')}`);
console.log(`运行: ${(os.uptime() / 3600).toFixed(1)} 小时`);
}
printStatus();