人人都会AI编程

10.1 process 进程对象

更新时间:2026-07-10

在任何 Node.js 应用中,process 都是一个全局可用的对象,无需 require。它提供了与当前进程进行交互的接口——读取环境变量、解析命令行参数、管理进程生命周期、监听系统信号等。可以说,process 是每个 Node.js 程序与操作系统直接对话的主要窗口。

本节将围绕开发者最常接触的几个方面展开:环境变量、命令行参数、进程退出、信号监听、标准输入输出以及进程工作目录。

10.1.1 环境变量:process.env

服务器应用经常需要根据部署环境切换配置(数据库地址、API 密钥、运行模式等),而环境变量是最通用的配置注入方式。process.env 是一个包含所有环境变量的键值对对象:

// 读取环境变量
const dbHost = process.env.DB_HOST || 'localhost';
const nodeEnv = process.env.NODE_ENV || 'development';

if (nodeEnv === 'production') {
  console.log('生产环境,连接数据库:', dbHost);
}

需要注意的是,process.env 中所有值都是字符串。如果要用布尔值或者数字,需要手动转换:

const port = parseInt(process.env.PORT, 10) || 3000;
const enableCache = process.env.ENABLE_CACHE === 'true';

通常项目会使用 dotenv 库从 .env 文件中加载环境变量,但它本质上还是在写入 process.env,因此这个全局对象是配置管理的最终储存地。

10.1.2 命令行参数:process.argv

Node.js 脚本可以通过命令行接收参数,这在开发 CLI 工具时尤其常用。process.argv 是一个数组,包含启动进程时的所有命令行参数:

// 运行命令:node app.js --port=8080 --name=api
console.log(process.argv);
// 输出类似:
// [ '/usr/local/bin/node', '/path/to/app.js', '--port=8080', '--name=api' ]

数组的前两个元素固定为 Node 可执行文件的路径和当前脚本文件的路径,从第三个元素开始才是真正的自定义参数。

原生 process.argv 解析稍显繁琐,小型脚本可以直接根据位置读取:

const args = process.argv.slice(2);
const port = args.find(arg => arg.startsWith('--port='))?.split('=')[1] || '3000';

但对于正式 CLI 项目,更建议使用 commanderyargsminimist 等库,它们能自动处理参数解析、默认值、帮助信息生成等问题。

10.1.3 进程工作目录:process.cwd()

process.cwd() 返回当前 Node 进程的工作目录(Current Working Directory),这个目录是相对路径解析的基准:

console.log('当前工作目录:', process.cwd());
// 用相对路径读写文件时,路径会基于此目录解析

需要警惕的是,工作目录不等于脚本文件所在目录。dirname 指向的是当前模块文件所在的目录,而 process.cwd() 是启动进程时所在的目录。例如,在 /home/user 下执行 node projects/app/main.js,则 dirname/home/user/projects/app,而 process.cwd()/home/user。在读取配置或构建路径时,务必选对参照系。

10.1.4 标准输入输出:stdin / stdout / stderr

process.stdinprocess.stdoutprocess.stderr 是三个可读写的流,分别对应进程的标准输入、标准输出和标准错误输出。

标准输出是最常用的日志出口:

process.stdout.write('这是一条普通输出\n');
console.log('实际上 console.log 内部调用的就是 process.stdout.write');

标准错误输出通常用于报告错误信息,很多日志系统会区分 stdout 和 stderr 以做出不同处理:

if (error) {
  process.stderr.write(`错误:${error.message}\n`);
}

标准输入可以让程序读取用户输入或管道传来的数据:

// 读取所有输入,拼接后输出
let inputData = '';

process.stdin.setEncoding('utf8');
process.stdin.on('data', (chunk) => {
  inputData += chunk;
});

process.stdin.on('end', () => {
  console.log('接收到输入:', inputData);
});

也可以使用 readline 内置模块更方便地逐行读取。

10.1.5 进程退出与退出码:process.exit()

process.exit([code]) 方法会立即终止当前进程,并返回一个退出码给操作系统。0 通常代表成功,非 0 代表失败或异常。

// 发生致命错误时退出
if (!config.dbUrl) {
  console.error('缺少必要配置:DB_URL');
  process.exit(1);
}

// 正常结束
console.log('任务完成');
process.exit(0);

需要注意,调用 process.exit() 会跳过事件循环中尚未执行的回调,直接结束进程。如果希望在退出前执行清理工作(关闭数据库连接、保存状态等),应该监听 exit 事件或使用更温和的退出方式——让事件循环自然结束。

exit 事件:当进程即将退出时触发,可以执行同步清理操作。⚠️ 该事件中只能使用同步代码,因为事件循环已不再运行。

process.on('exit', (code) => {
  console.log(`进程即将退出,退出码:${code}`);
  // 此处 fs.writeFileSync 等同步操作仍然可用
});

10.1.6 信号监听

操作系统可以通过信号与进程通信,比如 SIGINT(通常按下 Ctrl+C 触发)、SIGTERM(停止信号)。Node.js 允许我们监听这些信号并作出响应,尤其是实现“优雅关闭”(graceful shutdown)。

// 监听 SIGINT 信号(Ctrl+C)
process.on('SIGINT', () => {
  console.log('收到 SIGINT 信号,开始优雅关闭...');
  server.close(() => {
    console.log('HTTP 服务已关闭');
    process.exit(0);
  });
});

// 监听 SIGTERM,通常用于容器编排或进程管理工具发送的停止命令
process.on('SIGTERM', () => {
  console.log('收到 SIGTERM 信号,准备退出');
  // 执行清理工作后退出
  process.exit(0);
});

优雅关闭是生产环境的重要实践,它会确保正在处理的请求完成,释放连接池、关闭文件句柄等,然后再退出。忽略这些信号的程序可能会被强制杀死,造成数据丢失或客户端异常。

10.1.7 其他实用属性与场景

process 对象还封装了大量运行时信息,在监控、调试和自适应逻辑中非常有用:

  • process.pid:当前进程的 ID。
  • process.ppid:父进程的 ID(可通过此判断是否由另一个进程启动)。
  • process.uptime():进程已运行的秒数,常用于健康检查。
  • process.memoryUsage():返回内存使用详情(堆、外部等),是内存排查常用工具。
  • process.cpuUsage():返回用户和系统 CPU 时间,可用来计算 CPU 占用。
  • process.title:获取或设置进程标题,在 ps 命令中清晰标识不同 Worker。
console.log(`进程 ID: ${process.pid}`);
console.log(`运行时间: ${process.uptime()} 秒`);
console.log(`内存使用:`, process.memoryUsage());

在线上监控中,定期打印这些指标并上报,能帮助运维提前发现内存泄漏或性能瓶颈。例如,某些 APM 工具会在请求处理前记录 process.cpuUsage(),结束时对比差值,计算出单次请求的 CPU 消耗。

10.1.8 注意事项与最佳实践

  • 不要随意 process.exit():在库代码或中间件中调用 process.exit() 会直接杀死整个应用,十分危险;应将致命错误向上抛出交给顶层处理。
  • 异常退出码:建议团队统一定义退出码含义(例如 10 表示配置错误、20 表示数据库连接失败),以便监控系统识别。
  • 环境变量的安全:避免在日志中打印 process.env 全量内容,防止泄漏密钥。可使用滤波函数只输出与调试相关的变量。
  • 信号处理的可靠性:尽量不要在信号处理函数中做耗时异步操作,因为第二次收到同一信号时可能会强制退出;优先使用同步清理或快速异步操作配合 process.exit

process 进程对象就像是 Node 应用在操作系统中的“身份证”和“遥控器”。掌握它的常用 API,可以让你轻松应对配置管理、命令行工具开发、进程监控以及生产环境的优雅部署。在下一节中,我们将继续深入子进程模块,学习如何从 Node.js 中启动和管理外部进程。