在
Nodejs
中,process
是一个全局对象,它提供了与当前进程和运行时环境交互的方法和属性。通过process
对象,我们可以访问进程的信息、控制流程和进行进程间通信,这些都是服务端语言应该具备的能力。本文将全面介绍process
对象的使用场景,从基础概念到高级应用,带有代码示例,让您深入了解它的功能与用途。
公众号:Code程序人生,个人网站:https://creatorblog.cn
简单使用
首先,我们来看一些简单的process
对象的基础用法。
获取命令行参数
通过process.argv
属性可以获取命令行参数,其中argv[0]
是Nodejs
可执行文件的路径,argv[1]
是当前执行的脚本文件路径,后续元素是传递给脚本的命令行参数。
// process.js
console.log(process.argv);
执行以下命令:
node process.js arg1 arg2 arg3
输出结果:
结果分析:
[
'D:\\Nodejs\\node-v16.20.1-win-x86\\node.exe', // Nodejs可执行文件路径
'D:\\代码\\code-test\\process.js', // 当前执行的脚本路径
'arg1', // 命令行参数
'arg2',
'arg3'
]
获取环境变量
通过process.env
属性可以获取当前进程的环境变量,这在配置不同环境下的应用程序时非常有用。
写入环境变量的方式有很多很多,在前端通常在脚手架里通过cross-env来控制传入环境变量,今天我们写一个最容易演示的,直接在js文件里写入。
// env.js
process.env.NODE_ENV = 'production';
// process.js
require('./env');
console.log(process.env);
console.log(process.env.NODE_ENV);
执行以下命令:
node process.js
输出结果:
在正式的项目里,咱们可以通过判断环境变量所处的环境,比如开发环境、测试环境、生产环境,来做不同的应对,比如对请求后端接口的前置路径的控制等。
退出进程
通过process.exit()
方法可以使进程退出,接收一个可选的退出码参数。
// process.js
console.log("退出前");
process.exit(0);
console.log("退出后"); // 不会执行到这里
执行以下命令:
node process.js
输出结果:
结果分析:
从结果上来看,在输出 “退出前” 之后,通过process
提供的exit
方法退出此进程,导致后续并没有输出 “退出后”。
信号处理
通过process.on('SIGINT', callback)
方法可以捕获SIGINT
信号(通常由Ctrl+C
触发),从而实现对进程的优雅退出。
// process.js
process.on('SIGINT', () => {
console.log("接收到SIGINT信号。正在退出...");
process.exit(0);
});
console.log("正在等待SIGINT信号...");
setTimeout(() => {
}, 1000000);
因为要复现通过Ctrl + C
实现捕获SIGINT
信号的方式结束进程,所以我们需要让进程一直运行中,方式有很多,比如起一个web
服务等方式,最简单粗暴的,肯定还是使用定时器,给一个很大的延迟秒数,促使此进程不会很快结束,让我们可以手动通过Ctrl + C
捕获信号的形式来执行回调函数的内容。
执行以下命令:
node process.js
输出结果:
通过实际操作,可以复现既定的效果,让我们在进程结束之前通过回调函数做很多需要做的事情
进程间通信
在Nodejs
中,我们可以通过process
对象实现进程间通信,这对于父子进程之间的协作或者多个进程之间的数据传递都很有用。Nodejs
提供了child_process
模块来实现与子进程的交互。
子进程的创建与通信
通过spawn()
方法创建一个子进程,并通过stdin
、stdout
、stderr
来进行通信。
// process.js
const { spawn } = require('child_process');
const command = process.platform === 'win32' ? 'cmd.exe' : 'ls';
const args = process.platform === 'win32' ? ['/c', 'dir', '/b'] : ['-l'];
const childProcess = spawn(command, args);
childProcess.stdout.on('data', (data) => {
console.log(`子进程输出:\n${data}`);
});
childProcess.stderr.on('data', (data) => {
console.error(`子进程异常:\n${data}`);
});
childProcess.on('close', (code) => {
console.log(`子进程已退出,返回代码:${code}`);
});
在不同的操作系统和不同的系统位数中,相关处理可能不同,所以我们做了兼容。
执行以下命令:
node process.js
输出结果:
在上述示例中,我们创建了一个子进程来执行一些输出目录信息的命令,并通过stdout
和stderr
事件捕获子进程的输出和错误信息。close
事件在子进程退出时触发。
父进程与子进程之间的消息传递
除了通过标准输入输出进行通信外,父进程和子进程还可以通过消息传递的方式进行通信,Nodejs
提供了fork()
方法来创建具有IPC
通信的子进程。
// process.js
const { fork } = require('child_process');
const childProcess = fork('./child.js');
childProcess.on('message', (message) => {
console.log(`父进程收到消息: ${message}`);
});
childProcess.send('Hello,我是父进程!');
// child.js
process.on('message', (message) => {
console.log(`子进程收到消息: ${message}`);
process.send('你好,我是子进程!');
});
执行以下命令:
node process.js
输出结果:
进程信号与事件
Nodejs
中的process
对象提供了许多事件和信号,用于监听和处理进程相关的状态和事件。
exit事件
exit
事件在进程即将退出时触发,可以用来执行一些清理工作。
// process.js
process.on('exit', (code) => {
console.log(`进程将退出,返回的代码是: ${code}`);
});
console.log("开始!");
执行以下命令:
node process.js
输出结果:
uncaughtException事件
uncaughtException
事件用于捕获未被捕获的异常,但注意它不能替代正常的异常处理,只应该用于记录异常并尽量优雅地退出进程。
// process.js
process.on('uncaughtException', (err) => {
console.error(`未被捕获的异常: ${err.message}`);
// 这里可以进行一些异常处理逻辑
});
console.log("开始!");
// 模拟未被捕获的异常
throw new Error("出了问题");
console.log("这里不会被输出");
执行以下命令:
node process.js
输出结果:
warning事件
warning
事件用于捕获一些废弃的API
使用或其它可能导致问题的警告信息。
// process.js
process.on('warning', (warning) => {
console.warn(`警告: ${warning.message}`);
});
// 模拟发出一个废弃API的警告
process.emitWarning("这是不推荐使用的API用法,不推荐使用警告");
执行以下命令:
node process.js
输出结果:
beforeExit事件
beforeExit
事件在进程即将退出之前触发,可以用于执行一些异步操作,但不能阻止进程的退出。
process.on('beforeExit', (code) => {
console.log(`进程将退出,返回的代码是: ${code}`);
});
console.log("开始!");
// 模拟异步操作
setTimeout(() => {
console.log("已执行异步操作");
}, 1000);
执行以下命令:
node process.js
输出结果:
SIGINT信号
SIGINT
之前已经介绍过一次了。SIGINT
信号通常由Ctrl+C
触发,用于请求进程终止。我们可以捕获该信号,并实现优雅地退出进程。
// process.js
process.on('SIGINT', () => {
console.log("接收到SIGINT信号。正在退出...");
process.exit(0);
});
console.log("等待SIGINT信号...");
setTimeout(() => {
}, 1000000);
执行以下命令:
node process.js
输出结果:
SIGHUP、SIGTERM、SIGQUIT信号
除了SIGINT
信号,还有一些其他信号可以用于控制进程的行为,例如SIGHUP
、SIGTERM
和SIGQUIT
等。可以使用类似的方式捕获这些信号并实现相应的处理,这几个信号对于大部分人来说可能不常用,下面我简单叙述一下:
SIGHUP信号
SIGHUP(Hang Up)
信号通常在以下情况下发送给进程:
- 当终端连接(例如
SSH
会话)关闭时,与该终端关联的所有进程会收到SIGHUP
信号。 - 如果操作系统出现某些问题,导致终端会话意外终止,进程也可能收到
SIGHUP
信号。
默认情况下,对于大多数终端连接,SIGHUP
会终止进程。但是,您可以在Nodejs
中通过监听process
对象的SIGHUP
事件来处理这个信号,并在进程终止之前执行一些清理操作。
以下是一个简单的代码示例:
process.on('SIGHUP', () => {
console.log('收到SIGHUP信号。正在执行清理...');
// 执行清理操作,如关闭数据库连接、保存数据等
process.exit(0); // 可以选择退出进程,或执行其他操作
});
SIGTERM信号
SIGTERM
信号是由系统管理员或其他进程发送给进程,用于请求进程优雅地终止。SIGTERM
通常用于正常关闭进程,允许进程完成正在进行的操作并进行清理,然后自行终止。
在Nodejs
中,您可以通过监听process
对象的SIGTERM
事件来处理SIGTERM
信号,并在进程终止之前执行清理操作。
以下是一个简单的代码示例:
process.on('SIGTERM', () => {
console.log('收到SIGTERM信号。正在执行清理...');
// 执行清理操作,如关闭数据库连接、保存数据等
process.exit(0); // 可以选择退出进程,或执行其他操作
});
SIGQUIT信号
SIGQUIT
信号也是由系统管理员或其他进程发送给进程,用于请求进程终止,但与SIGTERM
不同的是,SIGQUIT
会产生core dump
文件,用于进程调试和故障排除。
在Nodejs
中,可以通过监听process
对象的SIGQUIT
事件来处理SIGQUIT
信号,并在进程终止之前执行一些清理操作。
以下是一个简单的代码示例:
process.on('SIGQUIT', () => {
console.log('收到SIGQUIT信号。正在执行清理...');
// 执行清理操作,如关闭数据库连接、保存数据等
process.exit(0); // 可以选择退出进程,或执行其他操作
});
请注意,这些信号的处理方式可以根据应用程序的需求进行自定义。对于SIGTERM
和SIGQUIT
信号,您可以在收到信号后执行清理操作,并自行决定是否退出进程。对于SIGHUP
信号,默认行为是终止进程,但您可以通过监听SIGHUP
信号并处理它来更改这种行为。
进程资源与性能
process
对象还提供了一些方法,用于获取当前进程的资源使用情况和性能指标。
获取内存使用情况
// process.js
const used = process.memoryUsage();
console.log(`Memory Usage:`);
console.log(` - RSS: ${used.rss} bytes`);
console.log(` - Heap Total: ${used.heapTotal} bytes`);
console.log(` - Heap Used: ${used.heapUsed} bytes`);
console.log(` - External: ${used.external} bytes`);
执行以下命令:
node process.js
输出结果:
获取CPU使用情况
// process.js
const startTime = process.hrtime();
setTimeout(() => {
const endTime = process.hrtime(startTime);
console.log(`CPU Usage:`);
console.log(` - Execution time: ${endTime[0]}s ${endTime[1] / 1000000}ms`);
}, 1000);
执行以下命令:
node process.js
输出结果:
设置进程标题与优先级
设置进程标题
// process.js
// 设置进程标题
process.title = "My Node.js App";
// 输出进程标题
console.log(process.title);
执行以下命令:
node process.js
输出结果:
设置进程优先级
在Nodejs
中,可以使用os
模块来设置进程的优先级。具体来说,可以使用os.priority()
方法来设置进程的调度优先级。
// process.js
const os = require('os');
// 设置进程的调度优先级为高
os.setPriority(os.constants.priority.PRIORITY_HIGH);
// 获取进程的调度优先级
const priority = os.getPriority();
console.log(`进程优先级: ${priority}`);
执行以下命令:
node process.js
输出结果:
注意
在Nodejs
中,os.getPriority()
方法返回的数值表示进程的调度优先级。不同的操作系统可能有不同的标准来表示进程优先级,但通常情况下,较小的负数值表示较高的优先级。
在Windows
系统中,优先级值的范围是 -15 到 15,其中 -15 表示最高优先级,15 表示最低优先级。因此,我在Nodejs
中使用os.getPriority()
方法返回值为 -14,那么在Windows系统中这个值表示的是接近最高优先级的状态。
需要注意的是,在不同的操作系统上,os.getPriority()
方法返回的值可能会有所不同。例如,Linux
操作系统上的优先级值范围可能是不同的,具体取决于操作系统的调度策略。
要实现跨平台的代码,最好避免硬编码特定操作系统的优先级值,而是根据需要使用更具有可移植性的方法和方式来设置进程优先级。如果你的应用程序需要使用特定优先级,请确保在不同操作系统上进行适当的测试和调整。
总结
process
对象是Nodejs
中非常重要的全局对象,提供了许多与进程和运行时环境交互的方法和属性。
在本文中,我们从基础的命令行参数获取和环境变量访问开始,逐步深入到进程间通信、信号处理、进程资源与性能等高级用法。
希望这篇博文能够帮助大家全面了解并灵活应用process
对象在Nodejs
应用程序开发中。