详解阿里Node.js技术文档之process模块学习指南
模块概览
process是node的全局模块,作用比较直观。可以通过它来获得node进程相关的信息,比如运行node程序时的命令行参数。或者设置进程相关信息,比如设置环境变量。
环境变量:process.env
使用频率很高,node服务运行时,时常会判断当前服务运行的环境,如下所示
if(process.env.NODE_ENV==='production'){ console.log('生产环境'); }else{ console.log('非生产环境'); }
运行命令NODE_ENV=productionnodeenv.js,输出如下
非生产环境
异步:process.nextTick(fn)
使用频率同样很高,通常用在异步的场景,来个简单的栗子:
console.log('海贼王'); process.nextTick(function(){ console.log('火影忍者'); }); console.log('死神'); //输出如下 //海贼王 //死神 //火影忍者
process.nextTick(fn)咋看跟setTimeout(fn,0)很像,但实际有实现及性能上的差异,我们先记住几个点:
- process.nextTick(fn)将fn放到node事件循环的下一个tick里;
- process.nextTick(fn)比setTimetout(fn,0)性能高;
获取命令行参数:process.argv
process.argv返回一个数组,数组元素分别如下:
- 元素1:node
- 元素2:可执行文件的绝对路径
- 元素x:其他,比如参数等
//printprocess.argv process.argv.forEach(function(val,index,array){ console.log('参数'+index+':'+val); });
运行命令NODE_ENV=devnodeargv.js--envproduction,输出如下。(不包含环境变量)
参数0:/Users/a/.nvm/versions/node/v6.1.0/bin/node
参数1:/Users/a/Documents/argv.js
参数2:--env
参数3:production
获取nodespecific参数:process.execArgv
跟process.argv看着像,但差异很大。它会返回nodespecific的参数(也就是运行node程序特有的参数啦,比如--harmony)。这部分参数不会出现在process.argv里。
我们来看个例子,相当直观。输入命令node--harmonyexecArgv.js--nickchyingp,execArgv.js代码如下:
process.execArgv.forEach(function(val,index,array){ console.log(index+':'+val); }); //输出: //0:--harmony process.argv.forEach(function(val,index,array){ console.log(index+':'+val); }); //输出: //0:/Users/a/.nvm/versions/node/v6.1.0/bin/node //1:/Users/a/Documents/execArgv.js //2:--nick //3:chyingp
当前工作路径:process.cwd()vsprocess.chdir(directory)
- process.cwd():返回当前工作路径
- process.chdir(directory):切换当前工作路径
工作路径的用途不用过多解释了,直接上代码:
console.log('Startingdirectory:'+process.cwd()); try{ process.chdir('/tmp'); console.log('Newdirectory:'+process.cwd()); } catch(err){ console.log('chdir:'+err); }
输出如下:
Startingdirectory:/Users/a/Documents/2016.11.22-node-process
Newdirectory:/private/tmp
IPC相关
- process.connected:如果当前进程是子进程,且与父进程之间通过IPC通道连接着,则为true;
- process.disconnect():断开与父进程之间的IPC通道,此时会将process.connected置为false;
首先是connected.js,通过fork创建子进程(父子进程之间创建了IPC通道)
varchild_process=require('child_process'); child_process.fork('./connectedChild.js',{ stdio:'inherit' });
然后,在connectedChild.js里面。
console.log('process.connected:'+process.connected); process.disconnect(); console.log('process.connected:'+process.connected); //输出: //process.connected:true //process.connected:false
其他
process.config:跟node的编译配置参数有关
标准输入/标准输出/标准错误输出:process.stdin、process.stdout
process.stdin、process.stdout、process.stderr分别代表进程的标准输入、标准输出、标准错误输出。看官网的例子
process.stdin.setEncoding('utf8'); process.stdin.on('readable',()=>{ varchunk=process.stdin.read(); if(chunk!==null){ process.stdout.write(`data:${chunk}`); } }); process.stdin.on('end',()=>{ process.stdout.write('end'); });
执行程序,可以看到,程序通过process.stdin读取用户输入的同时,通过process.stdout将内容输出到控制台
hello
data:hello
world
data:world
process.stderr也差不多,读者可以自己试下。
用户组/用户相关
process.seteuid(id):process.geteuid():获得当前用户的id。(POSIX平台上才有效)
process.getgid(id)process.getgid():获得当前群组的id。(POSIX平台上才有效,群组、有效群组的区别,请自行谷歌)
process.setegid(id)process.getegid():获得当前有效群组的id。(POSIX平台上才有效)
process.setroups(groups):process.getgroups():获得附加群组的id。(POSIX平台上才有效,
process.setgroups(groups):process.setgroups(groups):
process.initgroups(user,extra_group):
当前进程信息
- process.pid:返回进程id。
- process.title:可以用它来修改进程的名字,当你用ps命令,同时有多个node进程在跑的时候,作用就出来了。
运行情况/资源占用情况
process.uptime():当前node进程已经运行了多长时间(单位是秒)。
process.memoryUsage():返回进程占用的内存,单位为字节。输出内容大致如下:
{ rss:19181568, heapTotal:8384512,//V8占用的内容 heapUsed:4218408//V8实际使用了的内存 }
process.cpuUsage([previousValue]):CPU使用时间耗时,单位为毫秒。user表示用户程序代码运行占用的时间,system表示系统占用时间。如果当前进程占用多个内核来执行任务,那么数值会比实际感知的要大。官方例子如下:
conststartUsage=process.cpuUsage(); //{user:38579,system:6986} //spintheCPUfor500milliseconds constnow=Date.now(); while(Date.now()-now<500); console.log(process.cpuUsage(startUsage)); //{user:514883,system:11226}
process.hrtime():一般用于做性能基准测试。返回一个数组,数组里的值为[[seconds,nanoseconds](1秒等10的九次方毫微秒)。注意,这里返回的值,是相对于过去一个随机的时间,所以本身没什么意义。仅当你将上一次调用返回的值做为参数传入,才有实际意义。
把官网的例子稍做修改:
vartime=process.hrtime(); setInterval(()=>{ vardiff=process.hrtime(time); console.log(`Benchmarktook${diff[0]*1e9+diff[1]}nanoseconds`); },1000);
输出大概如下:
Benchmarktook1006117293nanoseconds
Benchmarktook2049182207nanoseconds
Benchmarktook3052562935nanoseconds
Benchmarktook4053410161nanoseconds
Benchmarktook5056050224nanoseconds
node可执行程序相关信息
process.version:返回当前node的版本,比如'v6.1.0'。
process.versions:返回node的版本,以及依赖库的版本,如下所示。
{http_parser:'2.7.0', node:'6.1.0', v8:'5.0.71.35', uv:'1.9.0', zlib:'1.2.8', ares:'1.10.1-DEV', icu:'56.1', modules:'48', openssl:'1.0.2h'}
process.release:返回当前node发行版本的相关信息,大部分时候不会用到。具体字段含义可以看这里。
{ name:'node', lts:'Argon', sourceUrl:'https://nodejs.org/download/release/v4.4.5/node-v4.4.5.tar.gz', headersUrl:'https://nodejs.org/download/release/v4.4.5/node-v4.4.5-headers.tar.gz', libUrl:'https://nodejs.org/download/release/v4.4.5/win-x64/node.lib' }
process.config:返回当前node版本编译时的参数,同样很少会用到,一般用来查问题。
process.execPath:node可执行程序的绝对路径,比如'/usr/local/bin/node'
进程运行所在环境
process.arch:返回当前系统的处理器架构(字符串),比如'arm','ia32',or'x64'。
process.platform:返回关于平台描述的字符串,比如darwin、win32等。
警告信息:process.emitWarning(warning);
v6.0.0新增的接口,可以用来抛出警告信息。最简单的例子如下,只有警告信息
process.emitWarning('Somethinghappened!'); //(node:50215)Warning:Somethinghappened!
可以给警告信息加个名字,便于分类
process.emitWarning('SomethingHappened!','CustomWarning'); //(node:50252)CustomWarning:SomethingHappened!
可以对其进行监听
process.emitWarning('SomethingHappened!','CustomWarning'); process.on('warning',(warning)=>{ console.warn(warning.name); console.warn(warning.message); console.warn(warning.stack); }); /* (node:50314)CustomWarning:SomethingHappened! CustomWarning SomethingHappened! CustomWarning:SomethingHappened! atObject.(/Users/a/Documents/git-code/nodejs-learning-guide/examples/2016.11.22-node-process/emitWarning.js:3:9) atModule._compile(module.js:541:32) atObject.Module._extensions..js(module.js:550:10) atModule.load(module.js:456:32) attryModuleLoad(module.js:415:12) atFunction.Module._load(module.js:407:3) atFunction.Module.runMain(module.js:575:10) atstartup(node.js:160:18) atnode.js:445:3 */
也可以直接给个Error对象
constmyWarning=newError('Warning!Somethinghappened!'); myWarning.name='CustomWarning'; process.emitWarning(myWarning);
向进程发送信号:process.kill(pid,signal)
process.kill()这个方法名可能会让初学者感到困惑,其实它并不是用来杀死进程的,而是用来向进程发送信号。举个例子:
console.log('hello'); process.kill(process.pid,'SIGHUP'); console.log('world');
输出如下,可以看到,最后一行代码并没有执行,因为向当前进程发送SIGHUP信号,进程退出所致。
hello
[1] 50856hangup nodekill.js
可以通过监听SIGHUP事件,来阻止它的默认行为。
process.on('SIGHUP',()=>{ console.log('GotSIGHUPsignal.'); }); console.log('hello'); process.kill(process.pid,'SIGHUP'); console.log('world');
测试结果比较意外,输出如下:(osx10.11.4),SIGHUP事件回调里的内容并没有输出。
hello
world
猜测是因为写标准输出被推到下一个事件循环导致(类似process.exit()小节提到的),再试下
process.on('SIGHUP',()=>{ console.log('GotSIGHUPsignal.'); }); setTimeout(function(){ console.log('Exiting.'); },0); console.log('hello'); process.kill(process.pid,'SIGHUP'); console.log('world');
输出如下(其实并不能说明什么。。。知道真相的朋友请举手。。。)
hello
world
Exiting.
GotSIGHUPsignal.
终止进程:process.exit([exitCode])、process.exitCode
- process.exit([exitCode])可以用来立即退出进程。即使当前有操作没执行完,比如process.exit()的代码逻辑,或者未完成的异步逻辑。
- 写数据到process.stdout之后,立即调用process.exit()是不保险的,因为在node里面,往stdout写数据是非阻塞的,可以跨越多个事件循环。于是,可能写到一半就跪了。比较保险的做法是,通过process.exitCode设置退出码,然后等进程自动退出。
- 如果程序出现异常,必须退出不可,那么,可以抛出一个未被捕获的error,来终止进程,这个比process.exit()安全。
来段官网的例子镇楼:
//Howtoproperlysettheexitcodewhileletting //theprocessexitgracefully. if(someConditionNotMet()){ printUsageToStdout(); process.exitCode=1; }
备注:整个process.exit()的接口说明,都在告诉我们process.exit()这个接口有多不可靠。。。还用吗。。。
事件
- beforeExit:进程退出之前触发,参数为exitCode。(此时eventLoop已经空了)如果是显式调用process.exit()退出,或者未捕获的异常导致退出,那么beforeExit不会触发。(我要,这事件有何用。。。)
- exit:
TODO待进一步验证
官方文档里,对于process.nextTick(fn)有如下描述,如何构造用例进行测试?
ItrunsbeforeanyadditionalI/Oevents(includingtimers)fireinsubsequentticksoftheeventloop.
process.channel:实际测试结果,即使父、子进程间存在IPC通道,process.channel的值依旧是undefined.(测试方法有问题?)
到此这篇关于详解阿里Node.js技术文档之process模块学习指南的文章就介绍到这了,更多相关Node.jsprocess模块内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!