IO.js Process

由 Janet 创建,路飞 最后一次修改 2016-02-24

process对象是一个全局对象,并且何以被在任何地方调用。这是一个EventEmitter实例。

Exit Codes

当没有任何异步操作在等待时,io.js通常将会以一个0为退出码退出。以下这些状态码会在其他情况下被用到:

  • 1 未捕获的致命异常。这是一个未捕获的异常,并且它没有被domain处理,也没有被uncaughtException处理。
  • 2 未使用(由Bash为内建误操作保留)。
  • 3 内部的JavaScript解析错误。io.js内部的JavaScript源码引导(bootstrapping)造成的一个解释错误。这极其罕见。并且常常只会发生在io.js自身的开发过程中。
  • 4 内部的JavaScript求值错误。io.js内部的JavaScript源码引导(bootstrapping)未能在求值时返回一个函数值。这极其罕见。并且常常只会发生在io.js自身的开发过程中。
  • 5 致命错误。这是V8中严重的不可恢复的错误。典型情况下,一个带有FATAL ERROR前缀的信息会被打印在stderr
  • 6 内部异常处理函数丧失功能。这是一个未捕获异常,但是内部的致命异常处理函数被设置为丧失功能,并且不能被调用。
  • 7 内部异常处理函数运行时失败。这是一个未捕获异常,并且内部致命异常处理函数试图处理它时,自身抛出了一个错误。例如它可能在当process.on('uncaughtException')domain.on('error')处理函数抛出错误时发生。
  • 8 未使用。io.js的之前版本中,退出码8通常表示一个未捕获异常。
  • 9 无效参数。当一个位置的选项被指定,或者一个必选的值没有被提供。
  • 10 内部的JavaScript运行时错误。io.js内部的JavaScript源码引导(bootstrapping)函数被调用时抛出一个错误。这极其罕见。并且常常只会发生在io.js自身的开发过程中。
  • 12 无效的调试参数。--debug和/或--debug-brk选项被设置,当时选择了一个无效的端口。
  • 大于128 信号退出。如果io.js收到了一个如SIGKILLSIGHUP的致命信号,那么它将以一个128加上 信号码的值 的退出码退出。这是一个标准的Unix实践,因为退出码由一个7位整数定义,并且信号的退出设置了一个高顺序位(high-order bit),然后包含一个信号码的值。

Event: 'exit'

进程即将退出时触发。在这个时刻已经没有办法可以阻止事件循环的退出,并且一旦所有的exit监听器运行结束时,进程将会退出。因此,在这个监听器中你仅仅能调用同步的操作。这是检查模块状态(如单元测试)的好钩子。回调函数有一个退出码参数。

例子:

process.on('exit', function(code) {
  // do *NOT* do this
  setTimeout(function() {
    console.log('This will not run');
  }, 0);
  console.log('About to exit with code:', code);
});

Event: 'beforeExit'

这个事件在io.js清空了它的事件循环并且没有任何已安排的任务时触发。通常io.js当没有更多被安排的任务时就会退出,但是beforeExit中可以执行异步调用,让io.js继续运行。

beforeExit在程序被显示终止时不会触发,如process.exit()或未捕获的异常。除非想去安排更多的任务,否则它不应被用来做为exit事件的替代。

Event: 'uncaughtException'

当一个异常冒泡回事件循环时就会触发。如果这个时间被添加了监听器,那么默认行为(退出程序且打印堆栈跟踪信息)将不会发生。

例子:

process.on('uncaughtException', function(err) {
  console.log('Caught exception: ' + err);
});

setTimeout(function() {
  console.log('This will still run.');
}, 500);

// Intentionally cause an exception, but don't catch it.
nonexistentFunc();
console.log('This will not run.');

注意,uncaughtException来处理异常是非常粗糙的。

请不要使用它,使用domain来替代。如果你已经使用了它,请在不处理这个异常之后重启你的应用。

请不要像io.jsError Resume Next这样使用。一个未捕获异常意味着你的应用或拓展有未定义的状态。盲目地恢复意味着任何事都可能发生。

想象你在升级你的系统时电源被拉断了。10次中前9次都没有问题,但是第10次时,你的系统崩溃了。

你已经被警告。

Event: 'unhandledRejection'

在一个事件循环中,当一个promise被“拒绝”并且没有附属的错误处理函数时触发。当一个带有promise异常的程序被封装为被“拒绝”的promise时,这样的程序的错误可以被promise.catch(...)捕获处理并且“拒绝”会通过promise链冒泡。这个事件对于侦测和保持追踪那些“拒绝”没有被处理的promise非常有用。这个事件会带着以下参数触发:

  • reason promise的“拒绝”对象(通常是一个错误实例)
  • p 被“拒绝”的promise

下面是一个把所有未处理的“拒绝”打印到控制台的例子:

process.on('unhandledRejection', function(reason, p) {
    console.log("Unhandled Rejection at: Promise ", p, " reason: ", reason);
    // application specific logging, throwing an error, or other logic here
});

下面是一个会触发unhandledRejection事件的“拒绝”:

somePromise.then(function(res) {
  return reportToUser(JSON.pasre(res)); // note the typo
}); // no `.catch` or `.then`

Event: 'rejectionHandled'

当一个Promise被“拒绝”并且一个错误处理函数被附给了它(如.catch())时的下一个事件循环之后触发。这个事件会带着以下参数触发:

  • p 一个在之前会被触发在unhandledRejection事件中,但现在被处理函数捕获的promise

一个promise链的顶端没有 “拒绝”可以总是被处理 的概念。由于其异步的本质,一个promise的“拒绝”可以在未来的某一个时间点被处理,可以是在事件循环中被触发unhandledRejection事件之后。

另外,不像同步代码中是一个永远增长的 未捕获异常 列表,promise中它是一个可伸缩的 未捕获拒绝 列表。在同步代码中,uncaughtException事件告诉你 未捕获异常 列表增长了。但是在promise中,unhandledRejection事件告诉你 未捕获“拒绝” 列表增长了,rejectionHandled事件告诉你 未捕获“拒绝” 列表缩短了。

使用“拒绝”侦测钩子来保持一个被“拒绝”的promise列表:

var unhandledRejections = [];
process.on('unhandledRejection', function(reason, p) {
    unhandledRejections.push(p);
});
process.on('rejectionHandled', function(p) {
    var index = unhandledRejections.indexOf(p);
    unhandledRejections.splice(index, 1);
});

Signal Events

当一个进程收到一个信号时触发。参阅sigaction(2)

监听SIGINT信号的例子:

// Start reading from stdin so we don't exit.
process.stdin.resume();

process.on('SIGINT', function() {
  console.log('Got SIGINT.  Press Control-D to exit.');
});

一个发送SIGINT信号的快捷方法是在大多数终端中按下 Control-C 。

注意:

  • SIGUSR1 是io.js用于开启调试的保留信号。可以为其添加一个监听器,但不能阻止调试的开始。
  • SIGTERM 和 SIGINT在非Windows平台下有在以 128 + 信号 退出码退出前重置终端模式的默认监听器。如果另有监听器被添加,默认监听器会被移除(即io.js将会不再退出)。
  • SIGPIPE 默认被忽略,可以被添加监听器。
  • SIGHUP 当控制台被关闭时会在Windows中产生,或者其他平台有其他相似情况时(参阅signal(7))。它可以被添加监听器,但是Windows中io.js会无条件的在10秒后关闭终端。在其他非Windows平台,它的默认行为是结束io.js,但是一旦被添加了监听器,默认行为会被移除。
  • SIGTERM 在Windows中不被支持,它可以被监听。
  • SIGINT 支持所有的平台。可以由 CTRL+C 产生(尽管它可能是可配置的)。当启用终端的raw mode时,它不会产生。
  • SIGBREAK 在Windows中,按下 CTRL+BREAK 时它会产生。在非Windows平台下,它可以被监听,但它没有产生的途径。
  • SIGWINCH 当终端被改变大小时产生。Windows下,它只会在当光标被移动时写入控制台或可读tty使用raw mode时发生。
  • SIGKILL 可以被添加监听器。它会无条件得在所有平台下关闭io.js
  • SIGSTOP 可以被添加监听器。

注意Windows不支持发送信号,但io.js通过process.kill()child_process.kill()提供了模拟:- 发送信号0被用来检查进程的存在 - 发送SIGINT, SIGTERM 和 SIGKILL 会导致目标进程的无条件退出。

process.stdout

一个指向stdout的可写流。

例如,console.log可能与这个相似:

console.log = function(msg) {
  process.stdout.write(msg + '\n');
};

io.js中,process.stderrprocess.stdout与其他流不同,因为他们不能被关闭(调用end()会报错)。它们永远不触发finish事件并且写操作通常是阻塞的。

  • 当指向普通文件或TTY文件描述符时,它们是阻塞的。

  • 以下情况下他们指向流

  • 他们在Linux/Unix中阻塞
  • 他们在Windows中的其他流里不阻塞

若要检查io.js是否在一个TTY上下文中运行,读取process.stderrprocess.stdoutprocess.stdinisTTY属性:

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

$ iojs -p "Boolean(process.stdout.isTTY)"
true
$ iojs -p "Boolean(process.stdout.isTTY)" | cat
false

更多信息请参阅tty文档。

process.stderr

一个指向stderr的可写流。

io.js中,process.stderrprocess.stdout与其他流不同,因为他们不能被关闭(调用end()会报错)。它们永远不触发finish事件并且写操作通常是阻塞的。

  • 当指向普通文件或TTY文件描述符时,它们是阻塞的。

  • 以下情况下他们指向流

  • 他们在Linux/Unix中阻塞
  • 他们在Windows中的其他流里不阻塞

process.stdin

一个指向stdin的可读流。

一个打开标准输入并且监听两个事件的例子:

process.stdin.setEncoding('utf8');

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

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

作为一个流,process.stdin可以被切换至“旧”模式,这样就可以兼容node.js v0.10 前所写的脚本。更多信息请参阅 流的兼容性 。

在“旧”模式中stdin流默认是被暂停的。所以你必须调用process.stdin.resume()来读取。注意调用process.stdin.resume()这个操作本身也会将流切换至旧模式。

如果你正将开启一个新的工程。你应该要更常使用“新”模式的流。

process.argv

一个包含了命令行参数的数组。第一次元素将会是'iojs',第二个元素将会是JavaScript文件名。之后的元素将会是额外的命令行参数。

// print process.argv
process.argv.forEach(function(val, index, array) {
  console.log(index + ': ' + val);
});

这将会是:

$ iojs process-2.js one two=three four
0: iojs
1: /Users/mjr/work/iojs/process-2.js
2: one
3: two=three
4: four

process.execPath

这将是开启进程的可执行文件的绝对路径名:

例子:

/usr/local/bin/iojs

process.execArgv

这是在启动时io.js自身参数的集合。这些参数不会出现在process.argv中,并且不会包含io.js可执行文件,脚本名和其他脚本名之后的参数。这些参数对开启和父进程相同执行环境的子进程非常有用。

例子:

$ iojs --harmony script.js --version

process.execArgv将会是:

['--harmony']

process.argv将会是:

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

process.abort()

这将导致io.js触发abort事件。这个将导致io.js退出,并创建一个核心文件。

process.chdir(directory)

为进程改变当前工作目录,如果失败,则抛出一个异常。

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

process.cwd()

返回进程的当前工作目录。

console.log('Current directory: ' + process.cwd());

process.env

包含用户环境变量的对象。参阅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/iojs' }

你可以改写这个对象,但是改变不会反应在你的进程之外。这以为着以下代码不会正常工作:

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

但是以下代码会:

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

process.exit([code])

使用指定的退出码退出程序,如果忽略退出码。那么将使用“成功”退出码0

以一个“失败”退出码结束:

process.exit(1);

在执行io.js的shell中可以看到为1的退出码。

process.exitCode

将是程序退出码的数字,当程序优雅退出 或 被process.exit()关闭且没有指定退出码时。

process.exit(code)指定一个退出码会覆盖之前的process.exitCode设置。

process.getgid()

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

获取进程的群组标识(参阅getgid(2))。这是一个群组id数组,不是群组名。

if (process.getgid) {
  console.log('Current gid: ' + process.getgid());
}

process.getegid()

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

获取进程的有效群组标识(参阅getgid(2))。这是一个群组id数组,不是群组名。

if (process.getegid) {
  console.log('Current gid: ' + process.getegid());
}

process.setgid(id)

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

设置进程的群组标识(参阅setgid(2))。它接受一个数字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);
  }
}

process.setegid(id)

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

设置进程的有效群组标识(参阅setgid(2))。它接受一个数字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);
  }
}

process.getuid()

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

获取进程的用户id(参阅getuid(2))。这是一个数字用户id,不是用户名。

if (process.getuid) {
  console.log('Current uid: ' + process.getuid());
}

process.geteuid()

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

获取进程的有效用户id(参阅getuid(2))。这是一个数字用户id,不是用户名。

if (process.geteuid) {
  console.log('Current uid: ' + process.geteuid());
}

process.setuid(id)

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

设置进程的用户ID(参阅setuid(2))。它接受一个数字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);
  }
}

process.seteuid(id)

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

设置进程的有效用户ID(参阅seteuid(2))。它接受一个数字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);
  }
}

process.getgroups()

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

返回一个补充群组ID的数组。如果包含了有效的组ID,POSIX将不会指定。但io.js保证它始终是。

process.setgroups(groups)

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

设置一个补充群组ID。这是一个特殊的操作,意味着你需要拥有rootCAP_SETGID权限才可以这么做。

列表可以包含群组ID,群组名,或两者。

process.initgroups(user, extra_group)

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

读取/etc/group并且初始化群组访问列表,使用用户是组员的所有群组。这是一个特殊的操作,意味着你需要拥有rootCAP_SETGID权限才可以这么做。

user是一个用户名或一个用户ID。extra_group是一个群组名或群组ID。

当你注销权限时有些需要关心的:

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 ]

process.version

一个暴露NODE_VERSION的编译时存储属性。

console.log('Version: ' + process.version);

process.versions

一个暴露io.js版本和它的依赖的字符串属性。

console.log(process.versions);

将可能打印:

{ http_parser: '2.3.0',
  node: '1.1.1',
  v8: '4.1.0.14',
  uv: '1.3.0',
  zlib: '1.2.8',
  ares: '1.10.0-DEV',
  modules: '43',
  openssl: '1.0.1k' }

process.config

一个表示用于编译当前io.js执行文件的配置的JavaScript对象。这和运行./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.kill(pid[, signal])

给进程传递一个信号。pid是进程id,signal是描述信号的字符串。信号码类似于'SIGINT''SIGHUP'。如果忽略,那么信号将是'SIGTERM'。更多信息参阅Signal Eventskill(2)

如果目标不存在将会抛出一个错误,并且在一些情况下,0信号可以被用来测试进程的存在。

注意,这个函数仅仅是名字为process.kill,它只是一个信号发送者。发送的信号可能与杀死进程无关。

一个发送信号给自身的例子:

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

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

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

注意:当SIGUSR1io.js收到,它会开始调试。参阅Signal Events

process.pid#

进程的PID。

console.log('This process is pid ' + process.pid);

process.title#

设置/获取 'ps' 中显示的进程名。

当设置该属性时,所能设置的字符串最大长度视具体平台而定,如果超过的话会自动截断。

在 Linux 和 OS X 上,它受限于名称的字节长度加上命令行参数的长度,因为它有覆盖参数内存。

v0.8 版本允许更长的进程标题字符串,也支持覆盖环境内存,但是存在潜在的不安全和混乱。

process.arch

返回当前的处理器结构:'arm''ia32''x64'

console.log('This processor architecture is ' + process.arch);

process.platform

放回当前的平台:'darwin''freebsd''linux''sunos''win32'

console.log('This platform is ' + process.platform);

process.memoryUsage()

返回当前io.js进程内存使用情况(用字节描述)的对象。

var util = require('util');

console.log(util.inspect(process.memoryUsage()));

可能的输出:

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

heapTotalheapUsed指向V8的内存使用。

process.nextTick(callback[, arg][, ...])

  • callback Function

在事件循环的下一次循环中调用回调函数。

这不是setTimeout(fn, 0)的简单别名,它更有效率。在之后的tick中,它在任何其他的I/O事件(包括timer)触发之前运行。

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

这对于开发你想要给予用户在对象被构建后,任何I/O发生前,去设置事件监听器的机会时,非常有用。

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

  process.nextTick(function() {
    this.startDoingStuff();
  }.bind(this));
}

var 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是危险的,如果你这样做:

maybeSync(true, function() {
  foo();
});
bar();

foo()bar()的调用次序是不确定的。

更好的做法是:

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

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

注意:nextTick队列在每一次事件循环的I/O开始前都要完全执行完毕。所以,递归地设置nextTick回调会阻塞I/O的方法,就像一个while(true);循环。

process.umask([mask])

设置或读取进程的文件模式的创建掩码。子进程从父进程中继承这个掩码。返回旧的掩码如果mask参数被指定。否则,会返回当前掩码。

var oldmask, newmask = 0022;

oldmask = process.umask(newmask);
console.log('Changed umask from: ' + oldmask.toString(8) +
            ' to ' + newmask.toString(8));

process.uptime()

io.js进程已执行的秒数。

process.hrtime()

[seconds, nanoseconds]元组数组的形式返回高分辨时间。是相对于过去的任意时间。它与日期无关所以不用考虑时区等因素。它的主要用途是衡量程序性能。

你可以将之前的process.hrtime()返回传递给一个新的process.hrtime()来获得一个比较。衡量性能时非常有用:

var time = process.hrtime();
// [ 1800216, 25 ]

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

  console.log('benchmark took %d nanoseconds', diff[0] * 1e9 + diff[1]);
  // benchmark took 1000000527 nanoseconds
}, 1000);

process.mainModule

检索require.main的备用方式。区别是,如果主模块在运行时改变,require.main可能仍指向改变发生前的被引入的原主模块。通常,假设它们一样是安全的。

require.main一样,当如果没有入口脚本时,它将是undefined

以上内容是否对您有帮助:
二维码
建议反馈
二维码