Skip to content

node之process体验 #3

Description

@junfeisu
No description provided.

Activity

  1. junfeisu commented on Sep 11, 2018

    @junfeisu
    OwnerAuthor

    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就是用来区分当前环境(测试环境、开发环境、线上环境)等

    那如何设置这些环境信息?

    1. process.env[xxx] = xxx
    2. 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)

    让我们看一下上面的结果是什么

    上述结果阐述

    1. process.kill(pid, signal),加入添加了对应signal的监听器,系统不会立刻同步执行process.emit('signal')
      所以我们会看到进程不是在发出信号之后,系统立刻执行监听函数。
    2. 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)

    运行结果如下:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions