Node.js Process
Node.js process 全局对象的核心 API:命令行参数、环境变量、退出码、信号处理、内存使用。
#concept
#growing
#backend
#nodejs
#javascript
[!info] related notes
- 所属 MOC: Node.js MOC
- 相关概念: Node.js 事件循环阶段
Node.js Process
一句话定义
process 是 Node.js 的全局对象,提供当前进程的信息和控制能力,无需 require。
命令行参数 process.argv
node app.js --name=test -v
// process.argv 是一个数组
// [0] = node 可执行文件路径
// [1] = 脚本文件路径
// [2...] = 用户传入的参数
console.log(process.argv);
// [
// '/usr/bin/node',
// '/path/to/app.js',
// '--name=test',
// '-v'
// ]
// 推荐用 parseArgs 解析(Node.js 18.3+)
import { parseArgs } from 'node:util';
const { values } = parseArgs({
args: process.argv.slice(2),
options: {
name: { type: 'string' },
verbose: { type: 'boolean', short: 'v' }
}
});
console.log(values.name); // 'test'
console.log(values.verbose); // true
环境变量 process.env
// 存在的环境变量值是字符串;缺失时为 undefined
console.log(process.env.NODE_ENV); // 'production'
console.log(process.env.PORT); // '3000'
// 修改当前进程环境;之后创建且继承该环境的子进程可见
// 不会修改父进程或已启动的子进程
process.env.DEBUG = 'true';
// 常见模式:带默认值
const port = Number(process.env.PORT ?? '3000');
if (!Number.isInteger(port) || port < 1 || port > 65535) {
throw new Error('PORT must be an integer from 1 to 65535');
}
const isProd = process.env.NODE_ENV === 'production';
// Windows 注意:环境变量名不区分大小写
// Linux/macOS 区分大小写
退出进程
process.exit(code) 请求立即退出,不等待异步清理,也可能截断尚未写完的 stdout/stderr。设置 process.exitCode 后停止接收任务、关闭仍活跃的资源,才能让进程自然退出。
process.exitCode = 1; // 示例:记录失败,随后让事件循环自然结束
process.on('beforeExit', (code) => {
console.log('事件循环已排空,退出码:', code);
});
process.on('exit', (code) => {
// 此处只做同步操作;安排异步任务不会使进程继续存活
});
beforeExit 可安排异步工作,从而延长进程生命并可能再次触发;它不会在显式 process.exit() 时触发。exit 回调则只能同步执行。不要把两者混为一谈。
信号处理
Unix 上常见 SIGINT 来自 Ctrl+C,SIGTERM 来自终止请求。安装处理器后,需要自行关闭资源并决定如何退出,不能只打印“优雅退出”。Windows 的信号支持不同,不能照搬 Unix 全部行为。
SIGHUP 可被程序约定为重载配置,但监听它只打印日志不会真的重载。完整服务关闭流程见 Node.js 服务的日志、健康检查与优雅退出。
内存使用
// 内存使用情况(单位:字节)
const usage = process.memoryUsage();
console.log({
rss: (usage.rss / 1024 / 1024).toFixed(2) + ' MB', // 常驻内存(RSS)
heapTotal: (usage.heapTotal / 1024 / 1024).toFixed(2) + ' MB', // V8 堆总量
heapUsed: (usage.heapUsed / 1024 / 1024).toFixed(2) + ' MB', // V8 堆已用
external: (usage.external / 1024 / 1024).toFixed(2) + ' MB', // 与 JS 对象关联的外部内存
arrayBuffers: (usage.arrayBuffers / 1024 / 1024).toFixed(2) + ' MB'
});
// 限制 V8 old space,不是整个进程 RSS 上限
// node --max-old-space-size=4096 app.js (单位 MB)
其他常用 API
// 进程信息
console.log(process.pid); // 进程 ID
console.log(process.ppid); // 父进程 ID
console.log(process.platform); // 'win32', 'linux', 'darwin'
console.log(process.arch); // 'x64', 'arm64'
console.log(process.version); // Node.js 版本
console.log(process.cwd()); // 当前工作目录
console.log(process.uptime()); // 进程运行时间(秒)
// 标准流
process.stdout.write('直接写入标准输出\n');
process.stderr.write('直接写入标准错误\n');
// nextTick 使用独立队列;与 Promise 的顺序需区分 CJS/ESM 上下文
process.nextTick(() => {
console.log('nextTick 回调');
});
常见误区
process.exit()是同步的:不会等待异步操作完成- 环境变量都是字符串:数字需要手动转换
- Windows 和 Linux 的信号不同:
SIGTERM在 Windows 上行为有限 process.chdir()影响之后按 cwd 解析的相对文件路径,不改变模块自身位置或已有打开的文件arrayBuffers计入external;两者相加会重复统计
学习检查
- 为什么设置
exitCode比立即exit()更适合有输出或清理的 CLI? beforeExit与exit哪个能延长事件循环生命?- 为什么增大
--max-old-space-size不能当作设置进程总内存上限?