Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node基础篇之进程process #35

Open
kekobin opened this issue Sep 19, 2019 · 0 comments
Open

Node基础篇之进程process #35

kekobin opened this issue Sep 19, 2019 · 0 comments

Comments

@kekobin
Copy link
Owner

kekobin commented Sep 19, 2019

简介

通过process能够获得node进程相关的信息,比如node运行时的命令行参数,当前环境变量等,在编写cli脚手架时特别有用。

process.env

一般在部署node项目时,不同的环境需要配置不同的环境变量,常用的是:

NODE_ENV=development

然后在业务逻辑中可以使用process.env获取到环境变量,进行不同的处理:

if(process.env.NODE_ENV === 'development') ...

process.nextTick(fn)

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:其他,比如参数等

在 G:\node-l目录先编写argv.js

process.argv.forEach((val, index, array) => {
  console.log('参数' + index + ': ' + val);
});

终端执行 node argv.js aaa bbb,结果如下:
image

process.cwd() vs process.chdir(directory)

  • process.cwd():返回当前工作路径
  • process.chdir(directory):切换当前工作路径

对于process.chdir(),一般在编写cli脚手架时,很多时候需要动态切换到别的目录作为当前的node进程目录,然后执行比如 npm install等。

IPC相关

  • process.connected:如果当前进程是子进程,且与父进程之间通过IPC通道连接着,则为true;
  • process.disconnect():断开与父进程之间的IPC通道,此时会将 process.connected 置为false;

首先是 connected.js,通过 fork 创建子进程(父子进程之间创建了IPC通道)

var child_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.stdin、process.stdout、process.stderr

分别代表进程的标准输入、标准输出、标准错误输出.

image

例子一: 输出用户输入的数据

process.stdin.setEncoding('utf8');

process.stdin.on('readable', () => {
  var chunk = process.stdin.read();
  if (chunk !== null) {
    process.stdout.write(`data: ${chunk}`);
  }
});

process.stdin.on('end', () => {
  process.stdout.write('end');
});

在终端启动 node std.js, 然后输入 hello, 将打印 data: hello。

例子二: 输出用户输入的a+b结果

// 默认情况下输入流是关闭的,要监听输入流数据,首先要开启输入流
process.stdin.resume();
var a;
var b;
process.stdout.write("请输入a的值:");
process.stdin.on('data',function(chunk){
    //判断用户输入的是a的值还是b的值
    if(!a){
        a = Number(chunk);
        process.stdout.write("请输入b的值:");
    }else{
        b = Number(chunk);
        process.stdout.write("结果等于"+(a+b));
    }
})

进程的输入输出方法

process.on('exit', function(code) { console.log(code) });
process.stdin.setEncoding('utf8');
 
process.stdout.write("......\n");
process.stdout.write("确认执行吗(y/n)?");
process.stdin.on('data',(input)=>{
  input = input.toString().trim();
  if (['Y', 'y', 'YES', 'yes'].indexOf(input) > -1) { console.log('console log -- yes')};
  if (['N', 'n', 'NO', 'no'].indexOf(input) > -1) process.exit(0);
})

node可执行程序相关信息

  • process.version:返回当前node的版本,比如'v6.1.0'。

  • process.versions:返回node的版本,以及依赖库的版本,如下所示。
    image

  • pocess.execPath: node可执行程序的绝对路径,比如 '/usr/local/bin/node'
    image

进程运行所在环境

  • process.arch:返回当前系统的处理器架构(字符串),比如'arm', 'ia32', or 'x64'。
  • process.platform:返回关于平台描述的字符串,比如 darwin、win32 等。

终止进程:process.exit([exitCode])、process.exitCode

  • process.exit([exitCode]) 可以用来立即退出进程。即使当前有操作没执行完,比如 process.exit() 的代码逻辑,或者未完成的异步逻辑。
  • 写数据到 process.stdout 之后,立即调用 process.exit() 是不保险的,因为在node里面,往 stdout 写数据是非阻塞的,可以跨越多个事件循环。于是,可能写到一半就跪了。比较保险的做法是,通过process.exitCode设置退出码,然后等进程自动退出。
  • 如果程序出现异常,必须退出不可,那么,可以抛出一个未被捕获的error,来终止进程,这个比 process.exit() 安全。

master-worker 多进程端口不会占用原理

node的cluster模块在fork代码时,不会报端口被占用,这是什么原因呢?
答案是:master进程监听了端口,而内部根据当前进程是否是worker把worker的listen给hack掉了,因为请求会先到达master,此时master把改请求根据负载均衡传递给某个worker,达到最终的效果。

模拟代码:

//master.js
onst fork = require('child_process').fork;
const cpus = require('os').cpus();
const server = require('net').createServer();
server.listen(3000);
process.title = 'node-master'

for (let i=0; i<cpus.length; i++) {
    const worker = fork('worker.js');
    // 重点是把master的server句柄传给了子进程
    worker.send('server', server);
}
// worker.js
const http = require('http');
const server = http.createServer((req, res) => {
    res.end('I am worker, pid: ' + process.pid + ', ppid: ' + process.ppid);
});// 注意:这里没有监听任何端口

let worker;
process.title = 'node-worker'
process.on('message', function (message, sendHandle) {
    if (message === 'server') {
        worker = sendHandle;
        // 使用master传过来的server,监听其请求,然后代理到子进程的server,就将该请求传给了该子进程
        worker.on('connection', function(socket) {
            server.emit('connection', socket);
        });
    }
});

net.Server都有connection事件,每次请求过来时,都会响应connection。

参考

Node.js process 模块解读

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant