Node.js v8.x 中文文档


process - 进程#

process 对象是一个全局变量,它提供当前 Node.js 进程的有关信息,以及控制当前 Node.js 进程。 因为是全局变量,所以无需使用 require()

process 事件#

process 对象是 EventEmitter 的实例。

'beforeExit' 事件#

当 Node.js 的事件循环数组已经为空,并且没有额外的工作被添加进来,事件 'beforeExit' 会被触发。 正常情况下,如果没有额外的工作被添加到事件循环数组,Node.js 进程会结束。 但是如果 'beforeExit' 事件绑定的监听器的回调函数中,含有一个可以进行异步调用的操作,那么 Node.js 进程会继续运行。

process.exitCode 作为唯一的参数值传递给 'beforeExit' 事件监听器的回调函数。

如果进程由于显式的原因而将要终止,例如直接调用 process.exit() 或抛出未捕获的异常,'beforeExit' 事件不会被触发。

除非本意就是需要添加额外的工作(比如通过监听器进行异步调用)到事件循环数组,否则不应该用 'beforeExit' 事件替代 'exit' 事件。

'disconnect' 事件#

如果 Node.js 进程是由 IPC 通道的方式创建的(详见子进程集群文档),当 IPC 通道关闭时,会触发'disconnect'事件。

'exit' 事件#

两种情况下 'exit' 事件会被触发:

  • 显式调用 process.exit() 方法,使得 Node.js 进程即将结束;
  • Node.js 事件循环数组中不再有额外的工作,使得 Node.js 进程即将结束。

在上述两种情况下,没有任何方法可以阻止事件循环的结束,一旦所有与 'exit' 事件绑定的监听器执行完成,Node.js 的进程会终止。

'exit' 事件监听器的回调函数,只有一个入参,这个参数的值可以是 process.exitCode 的属性值,或者是调用 process.exit() 方法时传入的 exitCode 值。

例如:

process.on('exit', (code) => {
  console.log(`即将退出,退出码:${code}`);
});

'exit' 事件监听器的回调函数,只允许包含同步操作。所有监听器的回调函数被调用后,任何在事件循环数组中排队的工作都会被强制丢弃,然后 Nodje.js 进程会立即结束。 例如在下例中,定时器中的操作永远不会被执行(因为不是同步操作)。

process.on('exit', (code) => {
  setTimeout(() => {
    console.log('该函数不会被执行');
  }, 0);
});

'message' 事件#

如果 Node.js 进程是由 IPC 通道的方式创建的(详见子进程集群文档),当子进程收到父进程发送的消息时(消息通过 childprocess.send() 发送),会触发 'message' 事件。

通过下列参数触发回调:

  • message <Object> 解析的 JSON 对象或原始值。
  • sendHandle <Handle object> 一个 net.Socketnet.Server 对象,或 undefined

注意: 这个消息经过序列化和解析,可能与原初发送的消息不完全一样。

'rejectionHandled' 事件#

如果有 Promise 被 rejected,并且此 Promise在 Node.js 事件循环的下次轮询及之后期间,被绑定了一个错误处理器(例如使用 promise.catch()),会触发 'rejectionHandled' 事件。

此事件监听器的回调函数使用 rejected 的 Promise 引用,作为唯一入参。

Promise 对象应该已经在 'unhandledRejection' 事件触发时被处理,但是在被处理过程中获得了一个 rejection 处理器。

对于 Promise 链,没有概念表明在 Promise 链的哪个地方,所有的 rejection 总是会被处理。 由于本来就是异步的,一个 Promise rejection 可以在将来的某个时间点被处理-可能要远远晚于 'unhandledRejection' 事件被触发及处理的时间。

另一种表述的方式就是,与使用同步代码时会出现不断增长的未处理异常列表不同,使用 Promise 时,未处理异常列表可能会出现增长然后收缩的情况。

在同步代码情况下,当未处理异常列表增长时,会触发 'uncaughtException' 事件。

在异步代码情况下,当未处理异常列表增长时,会触发 'uncaughtException' 事件,当未处理列表收缩时,会触发 'rejectionHandled' 事件。

例如:

const unhandledRejections = new Map();
process.on('unhandledRejection', (reason, p) => {
  unhandledRejections.set(p, reason);
});
process.on('rejectionHandled', (p) => {
  unhandledRejections.delete(p);
});

在上述例子中,unhandledRejections 会随着时间增加和缩减,表明 rejection 开始是未被处理状态,然后变成已处理状态。 可以定时(对于需长期运行的应用,这个可能是最好的方式)或当进程结束时(对脚本的应用可能是最方便的),在错误日志中记录这些错误信息。

'uncaughtException' 事件#

如果 Javascript 未捕获的异常,沿着代码调用路径反向传递回事件循环,会触发 'uncaughtException' 事件。 Node.js 默认情况下会将这些异常堆栈打印到 stderr 然后进程退出。 为 'uncaughtException' 事件增加监听器会覆盖上述默认行为。

'uncaughtException' 事件监听器的回调函数,使用 Error 对象作为唯一参数值。

例如:

process.on('uncaughtException', (err) => {
  fs.writeSync(1, `捕获到异常:${err}\n`);
});

setTimeout(() => {
  console.log('这里仍然会运行。');
}, 500);

// 故意调用一个不存在的函数,应用会抛出未捕获的异常。
nonexistentFunc();
console.log('这里不会运行。');

注意:正确地使用 uncaughtException#

需要注意,如果打算使用 'uncaughtException' 事件作为异常处理的最后补救机制,这是非常粗糙的设计方式。 此事件不应该当作 On Error Resume Next(出了错误就恢复让它继续)的等价机制。 未处理异常本身就意味着应用已经处于了未定义的状态。如果基于这种状态,尝试恢复应用正常进行,可能会造成未知或不可预测的问题。

此事件的监听器回调函数中抛出的异常,不会被捕获。为了避免出现无限循环的情况,进程会以非零的状态码结束,并打印堆栈信息。

如果在出现未捕获异常时,尝试去恢复应用,可能出现的结果与电脑升级时拔掉电源线出现的结果类似 -- 10次中有9次不会出现问题,但是第10次可能系统会出现错误。

正确使用 'uncaughtException' 事件的方式,是用它在进程结束前执行一些已分配资源(比如文件描述符,句柄等等)的同步清理操作。 触发 'uncaughtException' 事件后,用它来尝试恢复应用正常运行的操作是不安全的。

想让一个已经崩溃的应用正常运行,更可靠的方式应该是启动另外一个进程来监测/探测应用是否出错, 无论 uncaughtException 事件是否被触发,如果监测到应用出错,则恢复或重启应用。

'unhandledRejection' 事件#

如果在事件循环的一次轮询中,一个 Promise 被 rejected,并且此 Promise 没有绑定错误处理器,'unhandledRejection 事件会被触发。 当使用 Promise 进行编程时,异常会以 "rejected promises" 的形式封装。Rejection 可以被 promise.catch() 捕获并处理,并且在 Promise 链中传播。'unhandledRejection 事件在探测和跟踪 promise 被 rejected,并且 rejection 未被处理的场景中是很有用的。

此事件监听器的回调函数被传递如下参数:

  • reason <Error> | <any> 此对象包含了 promise 被 rejected 的相关信息(通常是一个 Error 对象)。
  • p 被 rejected 的 promise 对象。

例如:

process.on('unhandledRejection', (reason, p) => {
  console.log('未处理的 rejection:', p, '原因:', reason);
  // 记录日志、抛出错误、或其他逻辑。
});

somePromise.then((res) => {
  return reportToUser(JSON.pasre(res)); // 故意输错 `pasre`。
}); // 没有 `.catch` 或 `.then`。

如下代码也会触发'unhandledRejection'事件

function SomeResource() {
  // 将 loaded 的状态设置为一个 rejected promise。
  this.loaded = Promise.reject(new Error('错误信息'));
}

const resource = new SomeResource();
// resource.loaded 上没有 .catch 或 .then。

在例子中,可以像在其他 'unhandledRejection' 事件的典型场景中一样,跟踪开发者错误导致的 rejection。 为了解决这样的错误,resource.loaded 中可以加一个不做任何操作的 .catch(() => { }) 处理器, 这样可以阻止 'unhandledRejection' 事件的触发。或者也可以使用 'rejectionHandled' 事件来解决。

'warning' 事件#

任何时候Node.js发出进程告警,都会触发'warning'事件。

进程告警与进程错误的相似之处,在于两者都描述了需要引起用户注意的异常条件。 区别在于,告警不是Node.js和Javascript错误处理流程的正式组成部分。 一旦探测到可能导致应用性能问题,缺陷或安全隐患相关的代码实践,Node.js就可发出告警。

'warning'事件监听器的回调函数,参数只有一个,其值为Error 对象。此对象有三个重要的属性用来描述告警:

  • name <string> 告警的名称(目前默认值是 Warning)。
  • message <string> 系统提供的对此告警的描述。
  • stack <string> 当告警触发时,包含代码位置的堆栈信息。
process.on('warning', (warning) => {
  console.warn(warning.name);    // 打印告警名称
  console.warn(warning.message); // 打印告警信息
  console.warn(warning.stack);   // 打印堆栈信息
});

默认Node.js会打印进程告警到stderr。使用--no-warnings的命令行选项可以阻止默认从console输出信息, 但是'warning'事件仍然会被process对象发出。

下面的例子展示了当一个事件绑定了太多的监听器时,输出到stderr的告警。

$ node
> events.defaultMaxListeners = 1;
> process.on('foo', () => {});
> process.on('foo', () => {});
> (node:38638) MaxListenersExceededWarning: Possible EventEmitter memory leak
detected. 2 foo listeners added. Use emitter.setMaxListeners() to increase limit

与上述相反,如下例子关闭了默认的告警输出,并且给'warning'事件添加了一个定制的处理器。

$ node --no-warnings
> const p = process.on('warning', (warning) => console.warn('Do not do that!'));
> events.defaultMaxListeners = 1;
> process.on('foo', () => {});
> process.on('foo', () => {});
> Do not do that!

--trace-warnings命令行选项可以让默认的console输出告警信息时,包含告警的全部堆栈信息。

使用--throw-deprecation命令行选项标志启动Node.js,会使得custom deprecation warning作为异常信息抛出来。

使用--trace-deprecation命令行选项标志,会使得custom deprecation warning打印到stderr,包括其堆栈信息。

使用--no-deprecation命令行选项标志,会阻止报告所有的custom deprecation warning。

*-deprecation 命令行选项标志,只会影响使用名字为DeprecationWarning的告警。

触发自定义的告警#

查看process.emitWarning()的描述,其中包含关于触发定制告警或特定应用告警的信息。

信号事件#

当Node.js进程接收到一个信号时,会触发信号事件。 signal(7)列出了标准POSIX的信号名称列表,例如SIGINT, SIGHUP等等。

每个事件名称,以信号名称的大写表示 (比如事件'SIGINT' 对应信号 SIGINT).

例如:

// Begin reading from stdin so the process does not exit.
process.stdin.resume();

process.on('SIGINT', () => {
  console.log('Received SIGINT.  Press Control-D to exit.');
});
  • SIGUSR1 被Node.js保留用于启动调试器。可以为此事件绑定一个监听器,但是即使这样做也不会阻止调试器的启动。

  • SIGTERMSIGINT 在非windows平台绑定了默认的监听器,这样进程以代码128 + signal number结束之前,可以重置终端模式。 如果这两个事件任意一个绑定了新的监听器,原有默认的行为会被移除(Node.js不会结束)。

  • SIGPIPE 默认会被忽略。可以给其绑定监听器。

  • SIGHUP 在Windows平台中当console窗口被关闭时会触发它,在非windows平台中多种相似的条件下也会触发,查看signal(7)。 可以给其绑定监听器,但是Windows下Node.js会在它触发后10秒钟无条件关闭。 非windows平台,SIGHUP默认的绑定行为是结束Node.js,但是一旦给它绑定了新的监听器,默认行为会被移除。

  • SIGTERM 在Windows中不支持,可以给其绑定监听器。

  • SIGINT 在终端运行时,可以被所有平台支持,通常可以通过 <Ctrl>+C 触发(虽然这个不能配置)。 当终端运行在raw模式,它不会被触发。

  • SIGBREAK 在Windows中按下<Ctrl>+<Break>会被触发,非Windows平台中可以为其绑定监听器,但是没有方式触发或发送此事件。

  • SIGWINCH 当console被resize时会触发。Windows中只有当光标移动并写入到console,或者以raw模式使用一个可读tty时,才会触发。

  • SIGKILL 不能绑定监听器,所有平台中出现此事件,都会使得Node.js无条件终止。

  • SIGSTOP 不能绑定监听器。

  • SIGBUS, SIGFPE, SIGSEGV and SIGILL, 如果不是通过kill(2)产生,默认会使进程停留在某个状态,在此状态下尝试调用JS监听器是不安全的。 如果尝试调用JS监听器可能会导致进程在无限循环中挂死,因为使用process.on()附加的监听器是以异步的方式被调用,因此不能纠正隐含的问题。

Note: Windows不支持发送信号,但是Node.js通过process.kill(), 和 subprocess.kill()提供了某些模拟机制。 发送信号0 可以测试进程是否存在。发送SIGINT, SIGTERM, and SIGKILL 使得目标进程无条件终止。

process.abort()#

process.abort()方法会使Node.js进程立即结束,并生成一个core文件。

process.arch#

process.arch属性返回一个表示操作系统CPU架构的字符串,Node.js二进制文件是为这些架构编译的。 例如 'arm', 'arm64', 'ia32', 'mips', 'mipsel', 'ppc', 'ppc64', 's390', 's390x', 'x32', 或 'x64'

console.log(`This processor architecture is ${process.arch}`);

process.argv#

process.argv 属性返回一个数组,这个数组包含了启动Node.js进程时的命令行参数。第一个元素为process.execPath。如果需要获取argv[0]的值请参见 process.argv0。第二个元素为当前执行的JavaScript文件路径。剩余的元素为其他命令行参数。

例如,process-args.js文件有以下代码:

// print process.argv
process.argv.forEach((val, index) => {
  console.log(`${index}: ${val}`);
});

运行以下命令,启动进程:

$ node process-args.js one two=three four

将输出:

0: /usr/local/bin/node
1: /Users/mjr/work/node/process-args.js
2: one
3: two=three
4: four

process.argv0#

process.argv0属性,保存Node.js启动时传入的argv[0]参数值的一份只读副本。

$ bash -c 'exec -a customArgv0 ./node'
> process.argv[0]
'/Volumes/code/external/node/out/Release/node'
> process.argv0
'customArgv0'

process.channel#

如果Node.js进程是由IPC channel(请看 Child Process 文档) 方式创建的,process.channel属性保存IPC channel的引用。 如果IPC channel不存在,此属性值为undefined

process.chdir(directory)#

process.chdir()方法变更Node.js进程的当前工作目录,如果变更目录失败会抛出异常(例如,如果指定的目录不存在)。

console.log(`Starting directory: ${process.cwd()}`);
try {
  process.chdir('/tmp');
  console.log(`New directory: ${process.cwd()}`);
} catch (err) {
  console.error(`chdir: ${err}`);
}

process.config#

process.config 属性返回一个Javascript对象。此对象描述了用于编译当前Node.js执行程序时涉及的配置项信息。 这与执行./configure脚本生成的config.gypi文件结果是一样的。

可能的输出样例:

{
  target_defaults:
   { cflags: [],
     default_configuration: 'Release',
     defines: [],
     include_dirs: [],
     libraries: [] },
  variables:
   {
     host_arch: 'x64',
     node_install_npm: 'true',
     node_prefix: '',
     node_shared_cares: 'false',
     node_shared_http_parser: 'false',
     node_shared_libuv: 'false',
     node_shared_zlib: 'false',
     node_use_dtrace: 'false',
     node_use_openssl: 'true',
     node_shared_openssl: 'false',
     strict_aliasing: 'true',
     target_arch: 'x64',
     v8_use_snapshot: 'true'
   }
}

注意process.config属性值不是只读的,在Node.js生态系统中已经有模块扩展,修改或完全替换了process.config的值。

process.connected#

如果Node.js进程是由IPC channel方式创建的(请看[Child Process子进程][] 和 [Cluster集群][] 文档), 只要IPC channel保持连接,process.connected属性就会返回trueprocess.disconnect()被调用后,此属性会返回false

process.connected如果为false,则不能通过IPC channel使用process.send()发送信息。

process.cpuUsage([previousValue])#

process.cpuUsage()方法返回包含当前进程的用户CPU时间和系统CPU时间的对象。此对象包含usersystem属性,属性值的单位都是微秒(百万分之一秒)。 usersystem属性值分别计算了执行用户程序和系统程序的时间,如果此进程在执行任务时是基于多核CPU,值可能比实际花费的时间要大。

上一次调用process.cpuUsage()方法的结果,可以作为参数值传递给此方法,得到的结果是与上一次的差值。

const startUsage = process.cpuUsage();
// { user: 38579, system: 6986 }

// spin the CPU for 500 milliseconds
const now = Date.now();
while (Date.now() - now < 500);

console.log(process.cpuUsage(startUsage));
// { user: 514883, system: 11226 }

process.cwd()#

process cwd() 方法返回 Node.js 进程当前工作的目录。

console.log('Current directory: ${process.cwd()}');

process.disconnect()#

如果 Node.js 进程是从IPC频道派生出来的(具体看 Child ProcessCluster 的文档), process.disconnect()函数会关闭到父进程的IPC频道,以允许子进程一旦没有其他链接来保持活跃就优雅地关闭。

调用process.disconnect()的效果和父进程调用ChildProcess.disconnect()的一样ChildProcess.disconnect().

如果 Node.js 进程不是从IPC频道派生出来的,那调用process.disconnect()函数的结果是undefined.

process.emitWarning(warning[, options])#

  • warning <string> | <Error> 发出的警告。
  • options <Object>
    • type <string> 如果 warning 是String, type 是警告类型的名字。 默认值: Warning
    • code <string> 当前警告的唯一标识符。
    • ctor <Function> 如果warning是String,ctor是可选的function,用于限制生成的堆栈信息。默认process.emitWarning
    • detail <string> error的附加信息。

process.emitWarning()方法可用于发出定制的或应用特定的进程警告。 可以通过给process.on('warning')事件增加处理器,监听这些警告。

// Emit a warning with a code and additional detail.
process.emitWarning('Something happened!', {
  code: 'MY_WARNING',
  detail: 'This is some additional information'
});
// Emits:
// (node:56338) [MY_WARNING] Warning: Something happened!
// This is some additional information

在上面例子中,process.emitWarning()内部生成了一个Error对象,并传递给process.on('warning')事件。

process.on('warning', (warning) => {
  console.warn(warning.name);    // 'Warning'
  console.warn(warning.message); // 'Something happened!'
  console.warn(warning.code);    // 'MY_WARNING'
  console.warn(warning.stack);   // Stack trace
  console.warn(warning.detail);  // 'This is some additional information'
});

如果warning参数值是一个Error对象,options参数项都会被忽略。

process.emitWarning(warning[, type[, code]][, ctor])#

  • warning <string> | <Error> 发出的警告。
  • type <string> 如果 warning 是String, type 是警告类型的名字。 默认值: Warning
  • code <string> 当前警告的唯一标识符。
  • ctor <Function> 如果warning是String,ctor是可选的function,用于限制生成的堆栈信息。默认process.emitWarning

process.emitWarning()方法可用于发出定制的或应用特定的进程警告。 可以通过给process.on('warning')事件增加处理器,监听这些警告。

// Emit a warning using a string.
process.emitWarning('Something happened!');
// Emits: (node: 56338) Warning: Something happened!
// Emit a warning using a string and a type.
process.emitWarning('Something Happened!', 'CustomWarning');
// Emits: (node:56338) CustomWarning: Something Happened!
process.emitWarning('Something happened!', 'CustomWarning', 'WARN001');
// Emits: (node:56338) [WARN001] CustomWarning: Something happened!

在上面例子中,process.emitWarning()内部生成了一个Error对象,并传递给process.on('warning')事件。

process.on('warning', (warning) => {
  console.warn(warning.name);
  console.warn(warning.message);
  console.warn(warning.code);
  console.warn(warning.stack);
});

如果warning参数值是一个Error对象,它会被透传给process.on('warning')的事件监听器(可选参数值typecode and ctor会被忽略):

// Emit a warning using an Error object.
const myWarning = new Error('Something happened!');
// Use the Error name property to specify the type name
myWarning.name = 'CustomWarning';
myWarning.code = 'WARN001';

process.emitWarning(myWarning);
// Emits: (node:56338) [WARN001] CustomWarning: Something happened!

如果warning的参数值不是string或Error,会抛出 TypeError

需要注意的是,使用Error对象做为进程警告,并不是常用的错误处理机制的替代方式。

如果警告typeDeprecationWarning,会涉及如下额外的处理:

  • 如果命令行标识包含--throw-deprecation,deprecation warning会作为异常抛出,而不是作为事件被发出。

  • 如果命令行标识包含--no-deprecation,deprecation warning会被忽略。

  • 如果命令行标识包含--trace-deprecation,deprecation warning及其全部堆栈信息会被打印到stderr

Avoiding duplicate warnings#

作为最佳实践,警告应该在每个进程中最多发出一次。 为了达到上述的要求,推荐在使用emitWarning()之前用一个简单的布尔值做判断,如下例所示:

function emitMyWarning() {
  if (!emitMyWarning.warned) {
    emitMyWarning.warned = true;
    process.emitWarning('Only warn once!');
  }
}
emitMyWarning();
// Emits: (node: 56339) Warning: Only warn once!
emitMyWarning();
// Emits nothing

process.env#

process.env属性返回一个包含用户环境信息的对象 See environ(7).

例如这样的对象:

{
  TERM: 'xterm-256color',
  SHELL: '/usr/local/bin/bash',
  USER: 'maciej',
  PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin',
  PWD: '/Users/maciej',
  EDITOR: 'vim',
  SHLVL: '1',
  HOME: '/Users/maciej',
  LOGNAME: 'maciej',
  _: '/usr/local/bin/node'
}

可以修改这个对象,但是下面例子的做法是不会生效的:

$ node -e 'process.env.foo = "bar"' && echo $foo

下面的做法会生效:

process.env.foo = 'bar';
console.log(process.env.foo);

process.env中新增一个属性,会将属性值转换成字符串

例如:

process.env.test = null;
console.log(process.env.test);
// => 'null'
process.env.test = undefined;
console.log(process.env.test);
// => 'undefined'

deleteprocess.env中删除一个属性

例如:

process.env.TEST = 1;
delete process.env.TEST;
console.log(process.env.TEST);
// => undefined

在Windows系统下,环境变量是不区分大小写的

例如:

process.env.TEST = 1;
console.log(process.env.test);
// => 1

process.execArgv#

process.execArgv 属性返回当Node.js进程被启动时,Node.js特定的命令行选项。 这些选项在process.argv属性返回的数组中不会出现,并且这些选项中不会包括Node.js的可执行脚本名称或者任何在脚本名称后面出现的选项。 这些选项在创建子进程时是有用的,因为他们包含了与父进程一样的执行环境信息。

例如:

$ node --harmony script.js --version

process.execArgv的结果:

['--harmony']

process.argv的结果:

['/usr/local/bin/node', 'script.js', '--version']

process.execPath#

process.execPath 属性,返回启动Node.js进程的可执行文件所在的绝对路径。

例如:

'/usr/local/bin/node'

process.exit([code])#

  • code <integer> 结束状态码。默认为0

process.exit()方法以结束状态码code指示Node.js同步终止进程。 如果code未提供,此exit方法要么使用'success' 状态码 0,要么使用process.exitCode属性值,前提是此属性已被设置。 Node.js在所有'exit'事件监听器都被调用了以后,才会终止进程。

使用一个'failure'状态码结束的例子:

process.exit(1);

执行Node.js的shell应该会得到结束状态码1

调用 process.exit() 会强制进程尽快结束,即使仍然有很多处于等待中的异步操作没有全部执行完成, 包括输出到 process.stdoutprocess.stderr 的 I/O 操作。

在大多数情况下,显式调用process.exit()是没有必要的。如果在事件轮询队列中没有处于等待中的工作,Node.js进程会自行结束。 当进程正常结束时,process.exitCode属性可以被设置,以便于告知进程使用哪个结束状态码。

如下例子说明了一个 错误使用 process.exit()方法的场景,会导致输出到stdout的数据清空或丢失:

// This is an example of what *not* to do:
if (someConditionNotMet()) {
  printUsageToStdout();
  process.exit(1);
}

这个例子中出现问题的原因在于,Node.js中写入到process.stdout的操作有时是异步的,并可能在Node.js事件轮询的多个ticks中出现。 调用process.exit()会使得在写入stdout的额外操作执行之前,进程就被强制结束了。

与直接调用process.exit()相比,代码应该设置process.exitCode并允许进程自然的结束,以免事件轮询队列中存在额外的工作:

// How to properly set the exit code while letting
// the process exit gracefully.
if (someConditionNotMet()) {
  printUsageToStdout();
  process.exitCode = 1;
}

如果出现错误情况,而有必要结束Node.js进程,抛出一个uncaught错误并且允许进程正常结束的处理方式,要比调用process.exit()安全的多。

process.exitCode#

当进程正常结束,或通过process.exit()结束但未传递参数时,此数值标识进程结束的状态码。

process.exit(code)指定一个状态码,会覆盖process.exitCode的原有值。

process.getegid()#

process.getegid()方法返回Node.js进程的有效数字标记的组身份(See getegid(2))。

if (process.getegid) {
  console.log(`Current gid: ${process.getegid()}`);
}

注意:这个函数只在POSIX平台有效(在Windows或Android平台无效)。

process.geteuid()#

process.geteuid()方法返回Node.js进程的有效数字标记的用户身份(See geteuid(2))。

if (process.geteuid) {
  console.log(`Current uid: ${process.geteuid()}`);
}

注意:这个函数只在POSIX平台有效(在Windows或Android平台无效)。

process.getgid()#

process.getgid()方法返回Node.js进程的数字标记的组身份(See getgid(2))。

if (process.getgid) {
  console.log(`Current gid: ${process.getgid()}`);
}

注意:这个函数只在POSIX平台有效(在Windows或Android平台无效)。

process.getgroups()#

process.getgroups()方法返回数组,其中包含了补充的组ID。 如果包含有效的组ID,POSIX会将其保留为未指定状态,但 Node.js 会确保它始终处于状态。

注意:这个函数只在POSIX平台有效(在Windows或Android平台无效)。

process.getuid()#

process.getuid()方法返回Node.js进程的数字标记的用户身份(See getuid(2))。

if (process.getuid) {
  console.log(`Current uid: ${process.getuid()}`);
}

注意:这个函数只在POSIX平台有效(在Windows或Android平台无效)。

process.hrtime([time])#

  • time <Array> 上一次调用process.hrtime()的结果
  • Returns: <Array>

process.hrtime()方法返回当前时间以[seconds, nanoseconds] tuple Array表示的高精度解析值, nanoseconds是当前时间无法使用秒的精度表示的剩余部分。

time 是可选参数,传入的值是上一次调用process.hrtime()返回的结果,用于与当次调用做差值计算。 如果此参数传入的不是一个tuple Array,会抛出TypeError。 给此参数传入一个用户定义的数组,而不是传入上次调用process.hrtime()的结果,会导致未定义的行为。

process.hrtime()返回的时间,都是相对于过去某一时刻的值,与一天中的时钟时间没有关系,因此不受制于时钟偏差。 此方法最主要的作用是衡量间隔操作的性能:

const NS_PER_SEC = 1e9;
const time = process.hrtime();
// [ 1800216, 25 ]

setTimeout(() => {
  const diff = process.hrtime(time);
  // [ 1, 552 ]

  console.log(`Benchmark took ${diff[0] * NS_PER_SEC + diff[1]} nanoseconds`);
  // benchmark took 1000000552 nanoseconds
}, 1000);

process.initgroups(user, extra_group)#

process.initgroups()方法读取/etc/group文件,并且初始化组访问列表,该列表包括了用户所在的所有组。 该方法需要Node.js进程有root访问或者有CAP_SETGID capability才能操作。

替换gid并舍弃权限时需要格外谨慎。例如:

console.log(process.getgroups());         // [ 0 ]
process.initgroups('bnoordhuis', 1000);   // switch user
console.log(process.getgroups());         // [ 27, 30, 46, 1000, 0 ]
process.setgid(1000);                     // drop root gid
console.log(process.getgroups());         // [ 27, 30, 46, 1000 ]

注意:这个函数只在POSIX平台有效(在Windows或Android平台无效)。

process.kill(pid[, signal])#

  • pid <number> 进程ID
  • signal <string> | <number> 将发送的信号,类型为string或number。默认为'SIGTERM'

process.kill()方法将signal发送给pid标识的进程。

信号名称是如'SIGINT''SIGHUP'的字符串。更多信息,查看Signal Eventskill(2)

如果目标pid不存在,该方法会抛出错误。作为一个特殊例子,信号0可以用于测试进程是否存在。 在Windows平台中,如果pid用于kill进程组,会抛出错误。

注意:即使这个函数的名称是process.kill(),它其实只是发送信号,这点与kill系统调用类似。 发送的信号可能是做一些与kill目标进程无关的事情。

例如:

process.on('SIGHUP', () => {
  console.log('Got SIGHUP signal.');
});

setTimeout(() => {
  console.log('Exiting.');
  process.exit(0);
}, 100);

process.kill(process.pid, 'SIGHUP');

注意: 当Node.js进程接收到了SIGUSR1,Node.js会启动debugger,查看Signal Events

process.mainModule#

process.mainModule属性提供了一种获取require.main的替代方式。 区别在于,若主模块在运行时中发生改变, require.main可能仍然指向变化之前所依赖的模块 一般来说,假定require.mainprocess.mainModule引用相同的模块是安全的。

就像require.main一样,如果没有入口脚本,process.mainModule的值是undefined

process.memoryUsage()#

process.memoryUsage()方法返回Node.js进程的内存使用情况的对象,该对象每个属性值的单位为字节。

例如:

console.log(process.memoryUsage());

会得到:

{
  rss: 4935680,
  heapTotal: 1826816,
  heapUsed: 650472,
  external: 49879
}

heapTotalheapUsed 代表V8的内存使用情况。 external代表V8管理的,绑定到Javascript的C++对象的内存使用情况。 rss, 驻留集大小, 是给这个进程分配了多少物理内存(占总分配内存的一部分) 这些物理内存中包含堆,栈,和代码段。

对象,字符串,闭包等存于堆内存。 变量存于栈内存。 实际的JavaScript源代码存于代码段内存。

process.nextTick(callback[, ...args])#

  • callback <Function>
  • ...args <any> 调用 callback时传递给它的额外参数

process.nextTick()方法将 callback 添加到"next tick 队列"。 一旦当前事件轮询队列的任务全部完成,在next tick队列中的所有callbacks会被依次调用。

这种方式不是setTimeout(fn, 0)的别名。它更加有效率。事件轮询随后的ticks 调用,会在任何I/O事件(包括定时器)之前运行。

console.log('start');
process.nextTick(() => {
  console.log('nextTick callback');
});
console.log('scheduled');
// Output:
// start
// scheduled
// nextTick callback

此方法在开发如下API时非常重要:在对象构造好但还没有任何I/O发生之前,想给用户机会来指定某些事件处理器。

function MyThing(options) {
  this.setupOptions(options);

  process.nextTick(() => {
    this.startDoingStuff();
  });
}

const thing = new MyThing();
thing.getReadyForStuff();

// thing.startDoingStuff() gets called now, not before.

对于100%同步或100%异步的API,此方法也非常重要。考虑如下例子:

// WARNING!  DO NOT USE!  BAD UNSAFE HAZARD!
function maybeSync(arg, cb) {
  if (arg) {
    cb();
    return;
  }

  fs.stat('file', cb);
}

在如下场景中这个API是危险的:

const maybeTrue = Math.random() > 0.5;

maybeSync(maybeTrue, () => {
  foo();
});

bar();

因为不清楚foo()bar() 哪个会被先调用。

如下方式要更好一些:

function definitelyAsync(arg, cb) {
  if (arg) {
    process.nextTick(cb);
    return;
  }

  fs.stat('file', cb);
}

注意: 每次事件轮询后,在额外的I/O执行,next tick队列都会优先执行。 递归调用nextTick callbacks 会阻塞任何I/O操作,就像一个while(true); 循环一样。

process.noDeprecation#

The process.noDeprecation property indicates whether the --no-deprecation flag is set on the current Node.js process. See the documentation for the warning event and the emitWarning method for more information about this flag's behavior.

process.pid#

process.pid属性返回进程的PID。

console.log(`This process is pid ${process.pid}`);

process.platform#

process.platform属性返回字符串,标识Node.js进程运行其上的操作系统平台。

例如

  • 'aix'
  • 'darwin'
  • 'freebsd'
  • 'linux'
  • 'openbsd'
  • 'sunos'
  • 'win32'
console.log(`This platform is ${process.platform}`);

The value 'android' may also be returned if the Node.js is built on the Android operating system. However, Android support in Node.js is experimental.

process.ppid#

process.ppid 属性返回当前父进程的进程ID

console.log(`The parent process is pid ${process.ppid}`);

process.release#

process.release 属性返回与当前发布相关的元数据对象,包括源代码和源代码头文件 tarball的URLs。

process.release包括如下属性:

  • name <string> 对于Node.js, 此值始终为'node'。对于传统io.js 发布包, 此值为'io.js'

  • sourceUrl <string> 指向一个.tar.gz文件的绝对URL,包括了当前发布的源代码。

  • headersUrl <string> 指向一个.tar.gz文件的绝对URL,包括了当前发布的源代码的头文件信息。 这个文件要比全部源代码文件明显小很多,可以用于编译Node.js原生插件。

  • libUrl <string> 指向一个node.lib文件的绝对URL,匹配当前发布的结构和版本信息。此文件用于编译Node.js本地插件。 _这个属性只在Windows版本中存在,在其他平台中无效。

  • lts <string> 标识当前发布的LTS标签的字符串。 只有长效版(Long Term Support/LTS)存在这个属性,其他所有版本类型这个属性都是undefined, 包括Current版本,当前的有效值有:

    • 'Argon' for the 4.x LTS line beginning with 4.2.0.
    • 'Boron' for the 6.x LTS line beginning with 6.9.0.
    • 'Carbon' for the 8.x LTS line beginning with 8.9.1.

例如:

{
  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'
}

从源码树的非发布版本中构建的定制版本,可能只有name属性有效。其他的属性不一定会存在。

process.send(message[, sendHandle[, options]][, callback])#

如果Node.js进程是通过进程间通信产生的,那么,process.send()方法可以用来给父进程发送消息。 接收到的消息被视为父进程的ChildProcess对象上的一个'message'事件。

如果Node.js进程不是通过进程间通信产生的, process.send() 会是undefined

注意: 消息传递时,以格式序列化和解析,结果消息与发送时未必完全一样。

process.setegid(id)#

process.setegid()方法为进程设置有效的用户组ID。(请看 setegid(2).) id可以传一个数值ID或传一个用户组名称字符串。如果传了后者的话,会解析成一个相关的数值ID, 解析的时候,这个方法方法是阻塞的。

if (process.getegid && process.setegid) {
  console.log(`Current gid: ${process.getegid()}`);
  try {
    process.setegid(501);
    console.log(`New gid: ${process.getegid()}`);
  } catch (err) {
    console.log(`Failed to set gid: ${err}`);
  }
}

注意: 这个方法只在POSIX平台可用(换句话说,Windows或Android不行)。

process.seteuid(id)#

process.seteuid()方法为进程设置有效的用户ID。(请看 seteuid(2).) id可以传一个数值ID或传一个用户名字符串。如果传了特定的用户名字符串,会解析成一个相关的数值ID, 解析的时候,这个方法方法是阻塞的。

if (process.geteuid && process.seteuid) {
  console.log(`Current uid: ${process.geteuid()}`);
  try {
    process.seteuid(501);
    console.log(`New uid: ${process.geteuid()}`);
  } catch (err) {
    console.log(`Failed to set uid: ${err}`);
  }
}

注意: 这个方法只在POSIX平台可用(换句话说,Windows或Android不行)。

process.setgid(id)#

process.setgid() 为进程方法设置组ID. (查看setgid(2).) 可给id参数传一个数值ID或字符串名。

如果已经有一个进程组ID名,那么在解析为相关的ID之前,此方法是阻塞。

if (process.getgid && process.setgid) {
  console.log(`Current gid: ${process.getgid()}`);
  try {
    process.setgid(501);
    console.log(`New gid: ${process.getgid()}`);
  } catch (err) {
    console.log(`Failed to set gid: ${err}`);
  }
}

注意: 这个方法只在POSIX平台可用(换句话说,Windows或Android不行)。

process.setgroups(groups)#

The process.setgroups() method sets the supplementary group IDs for the Node.js process. This is a privileged operation that requires the Node.js process to have root or the CAP_SETGID capability.

The groups array can contain numeric group IDs, group names or both.

Note: This function is only available on POSIX platforms (i.e. not Windows or Android).

process.setuid(id)#

process.setuid(id) 设置进程的用户ID (参见 setuid(2).) id 可以是一个数值ID也可以是一个用户名字符串. 如果已经有一个用户名,在解析为相关的数值ID时,此方法阻塞。

if (process.getuid && process.setuid) {
  console.log(`Current uid: ${process.getuid()}`);
  try {
    process.setuid(501);
    console.log(`New uid: ${process.getuid()}`);
  } catch (err) {
    console.log(`Failed to set uid: ${err}`);
  }
}

注意: 这个方法只在POSIX平台可用(换句话说,Windows或Android不行)。

process.stderr#

process.stderr 属性返回连接到stderr(fd 2)的流。 它是一个net.Socket(它是一个Duplex流),除非 fd 2指向一个文件,在这种情况下它是一个[可写][]流。

注意: process.stderr 与其他 Node.js 流有重要的区别,详见 note on process I/O

process.stdin#

process.stdin 属性返回连接到 stdin (fd 0)的流。 它是一个net.Socket(它是一个Duplex流),除非 fd 0指向一个文件,在这种情况下它是一个Readable流。

举个例子:

process.stdin.setEncoding('utf8');

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

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

process.stdin 返回的 Duplex 流, 可以在模式下使用,兼容node v0.10。 更多信息查看流的兼容性

注意: 在"旧模式下" stdin流 默认是暂停的.所以必须通过执行.stdin.resume()来恢复它. 同时process.stdin.resume()会切换到旧模式

process.stdout#

process.stdout 属性返回连接到 stdout (fd 1)的流。 它是一个net.Socket (它是一个Duplex流), 除非 fd 1 指向一个文件,在这种情况下它是一个[可写][]流。

例1: 将输入流数据输出到输出流,即输出到终端。

process.stdin.pipe(process.stdout);

例2: 要求用户输入两个数值,然后把和输出到终端。

/*1:声明变量*/
var num1, num2;
/*2:向屏幕输出,提示信息,要求输入num1*/
process.stdout.write('请输入num1的值:');
/*3:监听用户的输入*/
process.stdin.on('data', function (chunk) {
    if (!num1) {
        num1 = Number(chunk);
        /*4:向屏幕输出,提示信息,要求输入num2*/
        process.stdout.write('请输入num2的值');
    } else {
        num2 = Number(chunk);
        process.stdout.write('结果是:' + (num1 + num2));
    }
});

注意: 重要的是process.stdout不同于 Node.js 的其他流, 详情可以参考note on process I/O .

A note on process I/O#

process.stdout and process.stderr 与 Node.js 中其他 streams 在重要的方面有不同:

  1. 他们分别使用内部的 console.log()console.error()
  2. 他们不能被关闭 (调用end()将会抛出异常)。
  3. 他们永远不会触发 'finish' 事件。
  4. 写操作是否为同步,取决于连接的是什么流以及操作系统是 Windows 还是 POSIX :

    • Files: 同步 在 Windows 和 POSIX 下
    • TTYs (Terminals): 异步 在 Windows 下, 同步 在 POSIX 下
    • Pipes (and sockets): 同步 在 Windows 下, 异步 在 POSIX 下

这些行为部分是历史原因,改变他们可能导致向后不兼容,而且他们的行为也符合部分用户的预期。

同步写避免了调用 console.log()console.error() 产生不符合预期的交错输出问题,或是在异步写完成前调用了process.exit()导致未写完整。 查看process.exit() 获取更多信息。

警告: 同步写将会阻塞事件循环直到写完成。 有时可能一瞬间就能写到一个文件,但当系统处于高负载时,管道的接收端可能不会被读取、缓慢的终端或文件系统,因为事件循环被阻塞的足够频繁且足够长的时间,这些可能会给系统性能带来消极的影响。当你向一个交互终端会话写时这可能不是个问题,但当生产日志到进程的输出流时要特别留心。

如果要检查一个流是否连接到了一个 TTY 上下文, 检查 isTTY 属性。

例如:

$ node -p "Boolean(process.stdin.isTTY)"
true
$ echo "foo" | node -p "Boolean(process.stdin.isTTY)"
false
$ node -p "Boolean(process.stdout.isTTY)"
true
$ node -p "Boolean(process.stdout.isTTY)" | cat
false

查看 TTY 文档以获得更多信息。

process.throwDeprecation#

process.throwDeprecation 属性表示--throw-deprecation标记是否被设置到当前Node.js进程上。 请查看 warning eventemitWarning method 的文档, 来获取这个标记行为的更多信息。

process.title#

process.title 属性用于获取或设置当前进程在 ps 命令中显示的进程名字

注意:当分配新值时,不同的平台会对标题施加不同的最大长度限制。 通常这种限制是相当有限的。 例如,在 Linux 和 macOS 上,process.title 仅限于二进制名称的大小加上命令行参数的长度,因为设置 process.title 会覆盖进程的argv内存。Node.js 的 v0.8, 通过覆盖 environ 允许内存较长的过程标题字符串,但是这在一些(相当模糊的)可能是不安全的并且令人困惑情况下。

process.traceDeprecation#

The process.traceDeprecation property indicates whether the --trace-deprecation flag is set on the current Node.js process. See the documentation for the warning event and the emitWarning method for more information about this flag's behavior.

process.umask([mask])#

process.umask()方法用于返回或设置Node.js进程的默认创建文件的权限掩码。子进程从父进程继承这个掩码。 不传参数时,默认返回当前掩码,如果传递了参数,创建文件掩码就被设置为参数值,并且返回之前的掩码。

const newmask = 0o022;
const oldmask = process.umask(newmask);
console.log(
  `Changed umask from ${oldmask.toString(8)} to ${newmask.toString(8)}`
);

process.uptime()#

process.uptime() 方法返回当前 Node.js 进程运行时间秒长

注意: 该返回值包含秒的分数。 使用 Math.floor() 来得到整秒钟。

process.version#

process.version 属性返回Node.js的版本信息。

console.log(`Version: ${process.version}`);

process.versions#

process.versions属性返回一个对象,此对象列出了Node.js和其依赖的版本信息。 process.versions.modules表明了当前ABI版本,此版本会随着一个C++API变化而增加。 Node.js会拒绝加载模块,如果这些模块使用一个不同ABI版本的模块进行编译。

console.log(process.versions);

会显示类似下面的对象信息:

{ http_parser: '2.7.0',
  node: '8.9.0',
  v8: '6.3.292.48-node.6',
  uv: '1.18.0',
  zlib: '1.2.11',
  ares: '1.13.0',
  modules: '60',
  nghttp2: '1.29.0',
  napi: '2',
  openssl: '1.0.2n',
  icu: '60.1',
  unicode: '10.0',
  cldr: '32.0',
  tz: '2016b' }

Exit Codes#

正常情况下,如果没有异步操作正在等待,那么Node.js会以状态码0退出,其他情况下,会 用如下的状态码:

  • 1 未捕获异常 - 有一个未被捕获的异常, 并且没被一个 domain 或 an 'uncaughtException' 事件处理器处理。
  • 2 - 未被使用 (Bash为防内部滥用而保留)
  • 3 内部JavaScript 分析错误 - Node.js的内部的JavaScript源代码 在引导进程中导致了一个语法分析错误。 这是非常少见的, 一般只会在开发Node.js本身的时候出现。
  • 4 内部JavaScript执行失败 - 引导进程执行Node.js的内部的JavaScript源代码时,返回函数值失败。 这是非常少见的, 一般只会在开发Node.js本身的时候出现。
  • 5 致命错误 - 在V8中有一个致命的错误. 比较典型的是以FATALERROR为前缀从stderr打印出来的消息。
  • 6 非函数的内部异常处理 - 发生了一个内部异常,但是内部异常处理函数 被设置成了一个非函数,或者不能被调用。
  • 7 内部异常处理运行时失败 - 有一个不能被捕获的异常。 在试图处理这个异常时,处理函数本身抛出了一个错误。 这是可能发生的, 比如, 如果一个 'uncaughtException' 或者 domain.on('error') 处理函数抛出了一个错误。
  • 8 - 未被使用. 在之前版本的Node.js, 退出码8有时候表示一个未被捕获的异常。
  • 9 - 不可用参数 - 也许是某个未知选项没有确定,或者没给必需要的选项填值。
  • 10 内部JavaScript运行时失败 - 调用引导函数时, 引导进程执行Node.js的内部的JavaScript源代码抛出错误。 这是非常少见的, 一般只会在开发Node.js本身的时候出现。
  • 12 不可用的调试参数 - --inspect 和/或 --inspect-brk 选项已设置,但选择的端口号无效或不可用。
  • >128 退出信号 - 如果Node.js的接收信号致命诸如 SIGKILLSIGHUP,那么它的退出代码将是 128 加上信号的码值。 这是POSIX的标准做法,因为退出码被定义为7位整数,并且信号退出设置高位,然后包含信号码值。