process
在 Node.js 里,process
属于全局对象,它能够提供与当前 Node.js 进程相关的各种信息和控制功能。借助 process
对象,你可以对环境变量进行访问、接收命令行参数、管理进程生命周期,还能与标准输入输出流进行交互:
1. 访问命令行参数
命令行参数可通过 process.argv
获取,这是一个包含所有命令行参数的数组。其中,argv[0]
是 Node.js 可执行文件的路径,argv[1]
是正在执行的 JavaScript 文件路径,从 argv[2]
开始才是真正传递给脚本的参数。
// args.js
console.log(process.argv);
// 执行命令:node args.js hello world
// 输出:['/usr/bin/node', '/path/to/args.js', 'hello', 'world']
2. 环境变量获取
通过 process.env
可以访问系统的环境变量,这在获取配置信息时非常有用。
// 获取环境变量 NODE_ENV
const env = process.env.NODE_ENV || 'development';
console.log(`当前环境是: ${env}`);
3. 进程信息与控制
process.pid
:用于获取当前进程的 ID。process.ppid
:可获取父进程的 ID。process.exit([code])
:能终止当前进程,并可选择返回退出码,默认退出码为 0。process.kill(pid, [signal])
:向指定 PID 的进程发送信号,这里的信号通常是字符串,像'SIGTERM'
就是常见的信号之一。
console.log(`当前进程 ID 是: ${process.pid}`);
// 2 秒后终止进程
setTimeout(() => {
process.exit(1); // 退出码 1 表示异常退出
}, 2000);
4. 标准输入输出流
process.stdout
:这是标准输出流,类似于console.log
,但它是原始流。process.stderr
:作为标准错误流,用于输出错误信息。process.stdin
:是标准输入流,可用于读取用户输入。
// 从标准输入读取数据
process.stdin.setEncoding('utf8');
process.stdin.on('readable', () => {
const chunk = process.stdin.read();
if (chunk !== null) {
process.stdout.write(`你输入的内容是: ${chunk}`);
}
});
process.stdin.on('end', () => {
process.stdout.write('结束输入\n');
});
5. 事件监听
process
对象可以监听多种事件,下面为你介绍几个重要事件:
beforeExit
:在 Node.js 事件循环队列为空,且没有异步操作挂起时触发。exit
:在进程即将退出前触发,此时无法再注册新的监听器。uncaughtException
:当未被捕获的异常冒泡到事件循环时触发。SIGINT
:在进程接收到Ctrl+C
信号时触发。
// 监听未捕获的异常
process.on('uncaughtException', (err) => {
console.error('捕获到未处理的异常:', err);
process.exit(1);
});
// 监听 Ctrl+C 信号
process.on('SIGINT', () => {
console.log('接收到 SIGINT 信号,正在优雅地退出...');
process.exit(0);
});
6. 资源使用情况
借助 process.memoryUsage()
可以获取进程的内存使用信息,该方法会返回一个包含以下字段的对象:
rss
(常驻内存集):是进程占用的总内存。heapTotal
:是 V8 堆的总大小。heapUsed
:是 V8 堆已使用的大小。external
:是 V8 外部资源(如 Node.js 绑定的 C++ 对象)使用的内存。
console.log('内存使用情况:', process.memoryUsage());
// 输出示例:
// {
// rss: 27705344,
// heapTotal: 6291456,
// heapUsed: 4154224,
// external: 90594
// }
7. 执行平台信息
process.platform
:可返回运行 Node.js 的平台,例如'win32'
'linux'
'darwin'
等。process.arch
:能返回 CPU 架构,像'x64'
'arm'
等。
console.log(`运行平台: ${process.platform}`);
console.log(`CPU 架构: ${process.arch}`);
8. 进程钩子
process.nextTick(callback)
:将回调函数放在当前事件循环的末尾执行,其优先级高于setImmediate
和setTimeout(0)
。setImmediate(callback)
:在当前 I/O 阶段完成后执行回调函数。
process.nextTick(() => {
console.log('nextTick 回调函数执行');
});
setImmediate(() => {
console.log('setImmediate 回调函数执行');
});
console.log('主线程代码执行');
// 输出顺序:
// 主线程代码执行
// nextTick 回调函数执行
// setImmediate 回调函数执行
总结
process
对象是 Node.js 中极为重要的一个全局对象,它为开发者提供了进程级别的控制和系统信息访问能力。无论是处理命令行参数、与标准输入输出流交互,还是管理进程生命周期,process
对象都发挥着关键作用。
process.env 详解
在 Node.js 里,process.env
是一个至关重要的全局对象,它主要用于存储和访问环境变量。环境变量作为操作系统提供给进程的键值对,在应用程序的配置过程中起着关键作用,像数据库连接字符串、API 密钥以及应用运行环境等配置信息,都可以通过环境变量来设置。下面将对 process.env
进行详细的分析。
1. 基本概念
环境变量是操作系统中存储的动态命名值,不同的操作系统,其环境变量的设置方式也有所不同。
- Windows:可以使用
set
命令来设置环境变量,例如set NODE_ENV=development
。 - Linux/macOS:使用
export
命令设置环境变量,如export NODE_ENV=development
。
在 Node.js 应用程序中,可以通过 process.env
对象来获取这些环境变量的值,获取方式为 process.env.VARIABLE_NAME
。
2. 常见应用场景
2.1 应用环境配置
在开发过程中,我们常常需要区分不同的运行环境,如开发环境、测试环境和生产环境。通过 process.env.NODE_ENV
就可以轻松实现这一区分。
const env = process.env.NODE_ENV || 'development';
if (env === 'production') {
// 生产环境配置
console.log('应用运行在生产环境');
} else if (env === 'development') {
// 开发环境配置
console.log('应用运行在开发环境');
}
2.2 敏感信息存储
为了保证应用程序的安全性,像数据库密码、API 密钥这类敏感信息不应该直接硬编码在代码中,而是应该通过环境变量来存储。
const dbConfig = {
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
};
2.3 端口配置
应用程序监听的端口也可以通过环境变量来设置,这样在不同的环境中就可以灵活调整端口号。
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`服务器运行在端口 ${port}`);
});
3. 环境变量的设置方法
3.1 命令行临时设置
在启动 Node.js 应用程序时,可以在命令行中临时设置环境变量,这种方式设置的环境变量仅在当前命令执行期间有效。
- Windows:
set VAR_NAME=value && node app.js
- Linux/macOS:
VAR_NAME=value node app.js
# Linux/macOS
NODE_ENV=production PORT=8080 node app.js
# Windows PowerShell
$env:NODE_ENV="production"; $env:PORT="8080"; node app.js
3.2 系统环境变量设置
可以在操作系统中永久设置环境变量,这样所有的应用程序都可以访问这些环境变量。
- Windows:通过系统属性 -> 高级系统设置 -> 环境变量进行设置。
- Linux/macOS:在
~/.bashrc
、~/.bash_profile
或~/.zshrc
文件中添加export VAR_NAME=value
。
3.3 使用 .env
文件(推荐做法)
在开发环境中,推荐使用 .env
文件来管理环境变量。需要安装 dotenv
包,它可以将 .env
文件中的变量加载到 process.env
中。
npm install dotenv
在项目根目录下创建 .env
文件:
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=secret
DB_NAME=mydb
API_KEY=your_api_key_here
在应用程序中加载 .env
文件:
require('dotenv').config();
// 现在可以访问 .env 文件中的变量
console.log(process.env.DB_HOST); // 输出: localhost
4. 特性与注意事项
4.1 数据类型
需要注意的是,process.env
中的所有值都是字符串类型。如果需要使用其他数据类型,如数字、布尔值等,需要进行显式的类型转换。
const port = parseInt(process.env.PORT, 10) || 3000;
const debug = process.env.DEBUG === 'true'; // 将字符串转换为布尔值
4.2 优先级
环境变量的设置存在一定的优先级顺序,从高到低依次为:命令行设置 > 系统环境变量 > .env
文件。如果同一个环境变量在多个地方都有设置,那么优先级高的设置会覆盖优先级低的设置。
4.3 安全性考量
- 敏感信息,如密码、密钥等,绝对不能提交到版本控制系统中。为了避免这种情况,应该在
.gitignore
文件中添加.env
文件。 - 在生产环境中,建议通过部署平台的安全机制来设置环境变量,而不是依赖
.env
文件。
4.4 运行时特性
process.env
是在运行时动态加载的,这意味着在应用程序运行期间对环境变量所做的修改会直接反映在 process.env
中。不过,一旦 Node.js 进程启动,通过代码对 process.env
所做的修改不会影响操作系统的环境变量。
// 修改运行时的环境变量
process.env.NEW_VAR = 'new_value';
console.log(process.env.NEW_VAR); // 输出: new_value
5. 最佳实践
5.1 使用默认值
为了保证应用程序的健壮性,在使用环境变量时,应该为其提供默认值。
const env = process.env.NODE_ENV || 'development';
const port = process.env.PORT || 3000;
5.2 统一配置管理
将所有的环境变量配置集中管理,避免在代码中分散引用 process.env
,这样可以提高代码的可维护性。
// config.js
module.exports = {
env: process.env.NODE_ENV || 'development',
database: {
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT, 10) || 5432,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
name: process.env.DB_NAME
},
apiKey: process.env.API_KEY
};
5.3 开发环境与生产环境分离
在开发环境中,可以使用 .env.development
、.env.production
等文件来区分不同环境的配置。在加载时,根据 NODE_ENV
来选择加载相应的配置文件。
const env = process.env.NODE_ENV || 'development';
require('dotenv').config({ path: `.env.${env}` });
6. dotenv
- dotenv:这是一个非常流行的模块,用于从
.env
文件加载环境变量。
dotenv
的注入机制本质上是:
- 读取文件 → 2. 解析内容 → 3. 合并到
process.env
。
- 从指定路径读取
.env
文件 - 将文件内容解析为键值对
- 将键值对注入到
process.env
中(默认不覆盖已存在的变量)
简单模拟
2.1 读取文件内容
使用 Node.js 的 fs
模块同步读取 .env
文件:
const fs = require('fs');
const path = require('path');
// 读取 .env 文件内容(默认路径为项目根目录)
const filePath = path.resolve(process.cwd(), '.env');
const content = fs.readFileSync(filePath, 'utf8');
2 解析键值对
将文件内容按行分割并解析为键值对:
function parse(src) {
const obj = {};
// 按行分割并处理
src.toString().split('\n').forEach(line => {
const match = line.match(/^([^=]+)=(.*)$/);
if (match) {
const key = match[1].trim();
// 处理引号包裹的值
let value = match[2].trim();
const maybeQuote = value[0];
if (maybeQuote === '"' || maybeQuote === "'") {
value = value.slice(1, -1);
}
obj[key] = value;
}
});
return obj;
}
const envConfig = parse(content);
3 注入到 process.env
将解析后的键值对合并到 process.env
中:
function config(options) {
try {
const parsed = parse(content);
// 合并到 process.env
Object.keys(parsed).forEach(key => {
// 只在变量未定义时注入(可通过 options.override 覆盖)
if (!process.env[key]) {
process.env[key] = parsed[key];
}
});
return { parsed };
} catch (e) {
return { error: e };
}
}
常见问题与注意事项
1 类型问题
process.env
中的值始终是字符串。例如:const debug = process.env.DEBUG; // 'true'(字符串) const isDebug = process.env.DEBUG === 'true'; // 需显式转换为布尔值
2 加载顺序
dotenv
必须在使用环境变量之前加载:// 错误:先使用后加载 console.log(process.env.DB_HOST); // 可能为 undefined require('dotenv').config(); // 正确:先加载后使用 require('dotenv').config(); console.log(process.env.DB_HOST); // 正确输出