Repository navigation
node之process体验 #3
Description
Activity
Node之process
process是Node环境下的一个全局对象,可以无需require直接使用。process是EventEmitter的一个实例,所以也可以进行事件的监听。process表示的是Node进程的进程对象,包含了当前进程的一些信息。比如进程id,进程的执行用户id,进程的输入输出,进程的环境参数等等。
process.env
process.env是一个包含用户环境信息的对象,介绍一下里面常见使用较多的参数
{ HOME: 'xxxx', // 表示系统当前用户的主目录 PWD: 'xxx', // 表示当前进程开始执行的路径 PATH: 'xxx', // 表示系统的环境变量 LOGNAME: 'xxx' // 表示当前用户名 }
补充: process.env.PWD在windows系统下是undefined,网上给出的解决方案说用process.cwd()进行替代,但是这样在某些情况下是不准确的。具体看process.env.PWD与process.cwd()的区别。
我自己目前整理出的解决方案就是在进程开始的时候进行判断process.env.PWD是不是undefined,是的话我们就自己设置一个参数叫PWD,值为process.cwd()的值
if (!process.env.PWD) { process.env.PWD = process.cwd() }
上面的前提成立的条件就是process.cwd() === process.env.PWD(类Unix系统里面),也就是进程没有执行切换目录的操作之前。
process.env强大的地方不在于已经列出的信息,而在于我们可以为当前进程自定义一些环境信息参数。
但是自定义的参数不会区分大小写,但是process.env里面自己封装的参数是区分大小写的像我们经常会用到的NODE_ENV,PORT,HOST等
NODE_ENV就是用来区分当前环境(测试环境、开发环境、线上环境)等那如何设置这些环境信息?
- process.env[xxx] = xxx
- npm script: set xxx = xxx(windows) || export xxx = xxx (Linux, Mac)
process.kill(pid, signal)
process.kill()用来向pid标识的进程发送相应的信号signal,进程接收到不同信号做出的响应也是不同的。比如:
SIGINT: 用来向进程发送中断信号(比如按下ctrl + c,node会自动向该进程发送SIGINT信号) SIGKILL: 该进程会无条件终止
了解更多信号请查看信号事件
有部分信号是支持监听器的,具体情况如下:process.on('SIGINT', () => { console.log('SIGINT signal emit') } process.kill(process.pid, 'SIGINT')
像上面的process.on('SIGINT')就是监听器,会监听发出的信号。
注意:SIGINT,SIGTERM信号在非Windows平台添加了默认的监听器,如果用户自己添加了新的监听器,系统的默认监听器就会失效,也就是说Node进程不会结束。所以如果想要加监听器,我们就必须手动在监听器里结束进程。让我们看一个具体的例子:
. 加了监听器没有手动结束进程process.on('SIGINT', () => { console.log('SIGINT') }) for (let i = 0; 10; i++) { if (i === 5) { process.kill(process.pid, 'SIGINT') } console.log(i) } setTimeout(() => { console.log('timeout') }, 1000)
上面的代码执行的结果是
我们加上退出process.exit()再看一下process.on('SIGINT', () => { console.log('SIGINT') process.exit() }) for (let i = 0; true; i++) { if (i === 5) { process.kill(process.pid, 'SIGINT') } console.log(i) } setTimeout(() => { console.log('timeout') }, 1000)
上述结果阐述
- process.kill(pid, signal),加入添加了对应signal的监听器,系统不会立刻同步执行process.emit('signal')
所以我们会看到进程不是在发出信号之后,系统立刻执行监听函数。 - process.on('SIGINT', fn)会移除Unix系统给SIGINT信号默认绑定的监听器,所以程序不会立刻退出。
那process.emit('signal')会在什么时候执行呢?或者说在Node事件循环哪个阶段执行?我们做一下下面的实验。
首先上一张Node官网给出的事件循环阶段图
简单说明:
timer 阶段执行到达时间的setTimeout和setInterval回调函数。
pending callbacks 执行延迟到下一个循环阶段的I/O事件
idle,prepare阶段 仅限系统内部执行
poll阶段 轮询阶段,io回调,网络请求回调等执行阶段然后我们使用下面的代码进行测试一下:
const fs = require('fs') process.on('SIGINT', () => { console.log('SIGINT') process.exit() }) for (let i = 0; i < 10; i++) { if (i === 5) { process.kill(process.pid, 'SIGINT') } console.log(i) } // 回调执行阶段:timer阶段 setTimeout(() => { console.log('timeout') }, 0) // 回调执行阶段:轮询(poll)阶段 fs.readFile('./package.json', (err, content) => { console.log('content') })
测试结果有两种情况:
从上面的结果图,我们可以知道,process.emit('signal')是执行在timer阶段之后,poll阶段之前,也就是在pending callback和idle,prepare阶段执行的,具体哪个阶段目前不清楚,个人倾向于在第三阶段执行。
如果想了解更多关于事件循环的,可以查看Node事件循环process.exit(exitCode)
process.exit()用来强制结束当前进程,不论是否还有操作是否没有被执行,exitCode(0|1)为0表示正常退出,1表示失败退出,这个exitCode是返回给启动当前进程的Shell,可以不写,默认为0。
同样我们可以为exit事件注册一个监听器process.on('exit'),但是与前面的不同的是:
即使注册了监听器之后,我们监听器的同步逻辑执行完就会立刻结束进程注:千万注意在监听器函数里所有的异步操作都是不会被执行的(包括process.nextTick),也就是说当主线程上的所有操作执行完,就立刻退出进程,不会进入事件循环阶段。
process.on('exit', () => { console.log('exit') process.nextTick(() => { console.log('nextTick') }) }) process.exit() setTimeout(() => { console.log('timeout') }, 0)




