本文深入解析Node.js中的process全局对象及其事件机制,包括exit和uncaughtException的处理。详细列举process模块的关键属性,如版本、平台、内存及PID等。重点对比child_process.exec与spawn方法,讲解如何创建子进程以利用多核CPU资源,并介绍相关配置选项与隔离性回调。
Node.js进程概述
尽管Node.js对操作系统进行了大量抽象封装,开发者仍可直接与其交互,例如与系统中已存在的进程通信或创建工作子进程。Node.js基于事件循环机制运行,但允许在事件循环之外创建其他进程(或线程)来分担工作负载。
进程模块
进程模块
process模块提供了获取或修改当前Node.js进程设置的功能。与其他模块不同,process是一个全局对象(代表Node主进程),开发者可以直接通过process变量访问它,无需额外引入。
process实现了EventEmitter接口,其exit事件会在进程退出时触发。需要注意的是,进程一旦退出便不再执行事件循环,因此只有那些没有回调函数的同步代码才会被执行。在下面的示例中,setTimeout内的语句将无法执行。
process.on('exit', function () {
setTimeout(function () {
console.log('This will not run');
}, 100);
console.log('Bye.');
});
在接触Node.js的过程中,你会发现影响主事件循环的异常会导致整个Node进程崩溃,这是一个严重的问题。为此,process提供了uncaughtException事件来处理此类异常,允许开发者捕获并处理这些错误,从而避免进程直接宕机。
process.on('uncaughtException', function (err) {
console.log('Caught exception: ' + err);
});
setTimeout(function () {
console.log('This will still run.');
}, 500);
// Intentionally cause an exception, but don't catch it.
nonexistentFunc();
console.log('This will not run.');
参考上述示例,我们注册了uncaughtException事件来捕捉系统异常。当代码执行到未定义的nonexistentFunc()时,会抛出异常。由于JavaScript是解释型语言,nonexistentFunc()之前的语句不受影响,但其后的语句不会执行。因此,输出结果如下:
Caught exception: ReferenceError: nonexistentFunc is not defined
This will still run.
再看一个具体的应用例子。
var http = require('http');
var server = http.createServer(function(req,res) {
res.writeHead(200, {});
res.end('response');
badLoggingCall('sent response');
console.log('sent response');
});
process.on('uncaughtException', function(e) {
console.log(e);
});
server.listen(8080);
在此示例中,我们创建了一个Web服务器。在处理完请求后,代码尝试执行不存在的badLoggingCall()方法,从而抛出异常。由于我们注册了uncaughtException事件来处理该异常,服务器不会受到影响,得以继续运行,并在服务器端记录错误日志。
[ReferenceError: badLoggingCall is not defined]
与当前进程交互
与当前进程交互
Node.js提供了一系列process属性,供开发者查询或设置进程状态,具体如下:
process.version:包含当前Node.js实例的版本号;
process.installPrefix:包含Node.js的安装路径;
process.platform:显示Node运行的操作系统环境,仅返回内核相关信息,例如linux2、darwin,而不会显示“Redhat ES3”、“Windows 7”或“OSX 10.7”等具体版本标识;
process.uptime():返回当前进程运行的时长(单位:秒);
process.getgid()和process.setgid():分别用于获取或设置进程组ID(group id);
process.getuid()和process.setuid():分别用于获取或设置用户ID(user id);
process.pid:获取当前进程的ID;
process.title:设置或获取进程名称;
process.execPath:返回当前Node.js进程的可执行文件路径,例如/usr/local/bin/node;
process.cwd():返回当前工作目录;
process.memoryUsage():报告Node.js进程的内存使用情况。其中rss代表物理内存(RAM)的使用情况,vsize代表总虚拟内存使用大小,包括RAM和交换空间(swap);
process.heapTotal和process.heapUsed:分别代表V8引擎分配的堆内存总量和当前正在使用的堆内存大小。
事件循环和ticker
事件循环和ticker
Node.js提供了process.nextTick()方法,允许开发者访问事件循环并延迟执行工作。它类似于setTimeout(),但会在下一次tick时立即执行,且每隔一段时间会执行一次。这里有一个示例:
var http = require('http');
var s = http.createServer(function(req, res) {
res.writeHead(200, {});
res.end('foo');
console.log('http response');
process.nextTick(function(){console.log('tick')});
});
s.listen(8000);
当有请求到来时,会依次记录日志“http response”和“tick”;当没有请求时,每隔一段时间执行事件循环,会输出“tick”。
此外,通过nextTick创建的回调函数具有隔离性,它们之间不会相互影响。
process.on('uncaughtException', function(e) {
console.log(e);
});
process.nextTick(function() {
console.log('tick');
});
process.nextTick(function() {
iAmAMistake();
console.log('tock');
});
process.nextTick(function() {
console.log('tick tock');
});
console.log('End of 1st loop');
在下面的示例中,首先输出“End of 1st loop”,然后按顺序执行nextTick的回调函数。第一个回调正常输出“tick”;第二个回调故意设置了一个异常,会输出异常信息,因此不会输出“tock”。得益于nextTick回调函数的隔离性,第三个回调仍会正常输出“tick tock”。运行结果如下:
End of 1st loop tick [ReferenceError: iAmAMistake is not defined] tick tock
子进程
子进程
Node.js提供了child_process模块,允许为主进程创建子进程,从而利用更多的服务器资源和CPU核心。这些概念在前面的章节中已有介绍。Node.js提供了child_process.spawn()和child_process.exec()两个方法来实现这一功能,下面将分别详细介绍。
child_process.exec( )
child_process.exec( )
来看exec的一个简单示例。它创建了一个子进程,第一个参数是Shell命令,第二个参数是回调函数,用于处理返回结果。
var cp = require('child_process');
cp.exec('ls -l', function(e, stdout, stderr) {
if(!e) {
console.log(stdout);
console.log(stderr);
}
});
exec()方法还可以接收options参数进行配置:
var options = {
encoding: 'utf8',
timeout: 0,
maxBuffer: 200 * 1024,
killSignal: 'SIGTERM',
setsid: false,
cwd: null,
env: null
};
var cp = require('child_process');
cp.exec('ls -l', options, function(e, stdout, stderr) {
if(!e) {
console.log(stdout);
console.log(stderr);
}
});
encoding:I/O流的编码格式;
timeout:进程超时时间;
killSignal:当时间或缓冲区超限时终止进程的信号;
maxBuffer:stdout或stderr可增长的最大值;
setsid:决定在进程中是否创建一个新的会话;
cwd:进程的初始工作目录,为null时表示使用Node.js的当前工作目录;
env:进程的环境变量。
child_process.spawn( )
child_process.spawn( )
child_process.spawn()比child_process.exec()更加强大和灵活,具体示例如下:
var cp = require('child_process');
var cat = cp.spawn('cat');
cat.stdout.on('data', function(d) {
console.log(d.toString());
});
cat.on('exit', function() {
console.log('kthxbai');
});
cat.stdin.write('meow');
cat.stdin.end();
以上所述是小编给大家介绍的nodejs中的process进程,希望对大家有所帮助!