首页 / Node.js 教程 / 辅助模块速览

Node.js 教程

辅助模块速览

本教程共 76 篇 · 第 25 篇 · 更新于 2026-07-25 · 约 6 分钟阅读

Node.jsosutilAbortControllerassert

25. 辅助模块速览

本节目标:os、util、timers、AbortController、assert 等辅助模块速览。

Node.js 内置了很多小而精的模块,单个拿出来不够写一整章,但日常开发里经常要用到。本章把 osutiltimersAbortControllerassert 五个模块快速过一遍,给你一张实用的速查表。

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

typeofinstanceof 更精确,尤其在跨 Realm(如 VM 模块创建的上下文)时更可靠。

parseArgs:命令行参数解析

v18.3+ 内置的命令行解析器,不需要装 minimistyargs

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 版

setTimeoutsetIntervalsetImmediate 在全局就能用,但 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();