Node.js process對象

2021-09-15 16:32 更新

process對象是Node的一個全局對象,提供當(dāng)前node進(jìn)程的信息。它可以在腳本的任意位置使用,不必通過require命令加載。該對象部署了EventEmitter接口。

進(jìn)程信息

通過process對象,可以獲知當(dāng)前進(jìn)程的很多信息。

退出碼

進(jìn)程退出時,會返回一個整數(shù)值,表示退出時的狀態(tài)。這個整數(shù)值就叫做退出碼。下面是常見的Node進(jìn)程退出碼。

  • 0,正常退出
  • 1,發(fā)生未捕獲錯誤
  • 5,V8執(zhí)行錯誤
  • 8,不正確的參數(shù)
  • 128 + 信號值,如果Node接受到退出信號(比如SIGKILL或SIGHUP),它的退出碼就是128加上信號值。由于128的二進(jìn)制形式是10000000, 所以退出碼的后七位就是信號值。

屬性

process對象提供一系列屬性,用于返回系統(tǒng)信息。

  • process.argv:返回當(dāng)前進(jìn)程的命令行參數(shù)數(shù)組。
  • process.env:返回一個對象,成員為當(dāng)前shell的環(huán)境變量,比如process.env.HOME。
  • process.installPrefix:node的安裝路徑的前綴,比如/usr/local,則node的執(zhí)行文件目錄為/usr/local/bin/node。
  • process.pid:當(dāng)前進(jìn)程的進(jìn)程號。
  • process.platform:當(dāng)前系統(tǒng)平臺,比如Linux。
  • process.title:默認(rèn)值為“node”,可以自定義該值。
  • process.version:Node的版本,比如v0.10.18。

下面是主要屬性的介紹。

stdout,stdin,stderr

以下屬性指向系統(tǒng)IO。

(1)stdout

stdout屬性指向標(biāo)準(zhǔn)輸出(文件描述符1)。它的write方法等同于console.log,可用在標(biāo)準(zhǔn)輸出向用戶顯示內(nèi)容。

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

下面代碼表示將一個文件導(dǎo)向標(biāo)準(zhǔn)輸出。

var fs = require('fs');

fs.createReadStream('wow.txt')
  .pipe(process.stdout);

上面代碼中,由于process.stdout和process.stdin與其他進(jìn)程的通信,都是流(stream)形式,所以必須通過pipe管道命令中介。

var fs = require('fs');
var zlib = require('zlib');

fs.createReadStream('wow.txt')
  .pipe(zlib.createGzip())
  .pipe(process.stdout);

上面代碼通過pipe方法,先將文件數(shù)據(jù)壓縮,然后再導(dǎo)向標(biāo)準(zhǔn)輸出。

(2)stdin

stdin代表標(biāo)準(zhǔn)輸入(文件描述符0)。

process.stdin.pipe(process.stdout)

上面代碼表示將標(biāo)準(zhǔn)輸入導(dǎo)向標(biāo)準(zhǔn)輸出。

由于stdin和stdout都部署了stream接口,所以可以使用stream接口的方法。

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');
});

(3)stderr

stderr屬性指向標(biāo)準(zhǔn)錯誤(文件描述符2)。

argv,execPath,execArgv

argv屬性返回一個數(shù)組,由命令行執(zhí)行腳本時的各個參數(shù)組成。它的第一個成員總是node,第二個成員是腳本文件名,其余成員是腳本文件的參數(shù)。

請看下面的例子,新建一個腳本文件argv.js。

// argv.js
console.log("argv: ",process.argv);

在命令行下調(diào)用這個腳本,會得到以下結(jié)果。

$ node argv.js a b c
[ 'node', '/path/to/argv.js', 'a', 'b', 'c' ]

上面代碼表示,argv返回數(shù)組的成員依次是命令行的各個部分,真正的參數(shù)實(shí)際上是從process.argv[2]開始。要得到真正的參數(shù)部分,可以把a(bǔ)rgv.js改寫成下面這樣。

// argv.js
var myArgs = process.argv.slice(2);
console.log(myArgs);

execPath屬性返回執(zhí)行當(dāng)前腳本的Node二進(jìn)制文件的絕對路徑。

> process.execPath
'/usr/local/bin/node'
>

execArgv屬性返回一個數(shù)組,成員是命令行下執(zhí)行腳本時,在Node可執(zhí)行文件與腳本文件之間的命令行參數(shù)。

# script.js的代碼為
# console.log(process.execArgv);
$ node --harmony script.js --version

方法

process對象提供以下方法:

  • process.chdir():切換工作目錄到指定目錄。
  • process.cwd():返回運(yùn)行當(dāng)前腳本的工作目錄的路徑。
  • process.exit():退出當(dāng)前進(jìn)程。
  • process.getgid():返回當(dāng)前進(jìn)程的組ID(數(shù)值)。
  • process.getuid():返回當(dāng)前進(jìn)程的用戶ID(數(shù)值)。
  • process.nextTick():指定回調(diào)函數(shù)在當(dāng)前執(zhí)行棧的尾部、下一次Event Loop之前執(zhí)行。
  • process.on():監(jiān)聽事件。
  • process.setgid():指定當(dāng)前進(jìn)程的組,可以使用數(shù)字ID,也可以使用字符串ID。
  • process.setuid():指定當(dāng)前進(jìn)程的用戶,可以使用數(shù)字ID,也可以使用字符串ID。

process.cwd(),process.chdir()

cwd方法返回進(jìn)程的當(dāng)前目錄,chdir方法用來切換目錄。

> process.cwd()
'/home/aaa'

> process.chdir('/home/bbb')
> process.cwd()
'/home/bbb'

process.nextTick()

process.nextTick()將任務(wù)放到當(dāng)前執(zhí)行棧的尾部。

process.nextTick(function () {
    console.log('下一次Event Loop即將開始!');
});

上面代碼可以用setTimeout(f,0)改寫,效果接近,但是原理不同。setTimeout(f,0)是將任務(wù)放到當(dāng)前任務(wù)隊列的尾部,在下一次Event Loop時執(zhí)行。另外,nextTick的效率更高,因為不用檢查是否到了指定時間。

setTimeout(function () {
   console.log('已經(jīng)到了下一輪Event Loop!');
}, 0)

process.exit()

process.exit方法用來退出當(dāng)前進(jìn)程,它可以接受一個數(shù)值參數(shù)。如果參數(shù)大于0,表示執(zhí)行失敗;如果等于0表示執(zhí)行成功。

if (err) {
  process.exit(1);
} else {
  process.exit(0);
}

process.exit()執(zhí)行時,會觸發(fā)exit事件。

process.on()

process.on方法用來監(jiān)聽各種事件,并指定回調(diào)函數(shù)。

process.on('uncaughtException', function(err){
  console.log('got an error: %s', err.message);
  process.exit(1);
});

setTimeout(function(){
  throw new Error('fail');
}, 100);

上面代碼是process監(jiān)聽Node的一個全局性事件uncaughtException,只要有錯誤沒有捕獲,就會觸發(fā)這個事件。

process支持的事件有以下一些。

  • data事件:數(shù)據(jù)輸出輸入時觸發(fā)
  • SIGINT事件:接收到系統(tǒng)信號時觸發(fā)
process.on('SIGINT', function () {
  console.log('Got a SIGINT. Goodbye cruel world');
  process.exit(0);
});

使用時,向該進(jìn)程發(fā)出系統(tǒng)信號,就會導(dǎo)致進(jìn)程退出。

$ kill -s SIGINT [process_id]

SIGTERM信號表示內(nèi)核要求當(dāng)前進(jìn)程停止,進(jìn)程可以自行停止,也可以忽略這個信號。

var http = require('http');

var server = http.createServer(function (req, res) {
});

process.on('SIGTERM', function () {
  server.close(function () {
    process.exit(0);
  });
});

上面代碼表示,進(jìn)程接到SIGTERM信號之后,關(guān)閉服務(wù)器,然后退出進(jìn)程。需要注意的是,這時進(jìn)程不會馬上退出,而是要回應(yīng)完最后一個請求,處理完所有回調(diào)函數(shù),然后再退出。

process.kill()

process.kill方法用來對指定ID的線程發(fā)送信號,默認(rèn)為SIGINT信號。

process.on('SIGTERM', function(){
    console.log('terminating');
    process.exit(1);
});

setTimeout(function(){
    console.log('sending SIGTERM to process %d', process.pid);
    process.kill(process.pid, 'SIGTERM');
}, 500);

setTimeout(function(){
    console.log('never called');
}, 1000);

上面代碼中,500毫秒后向當(dāng)前進(jìn)程發(fā)送SIGTERM信號(終結(jié)進(jìn)程),因此1000毫秒后的指定事件不會被觸發(fā)。

事件

exit事件

當(dāng)前進(jìn)程退出時,會觸發(fā)exit事件,可以對該事件指定回調(diào)函數(shù)。

process.on('exit', function () {
  fs.writeFileSync('/tmp/myfile', '需要保存到硬盤的信息');
});

注意,此時回調(diào)函數(shù)只能執(zhí)行同步操作,不能包含異步操作,因為執(zhí)行完回調(diào)函數(shù),進(jìn)程就會退出,無法監(jiān)聽到回調(diào)函數(shù)的操作結(jié)果。

process.on('exit', function(code) {
  // 不會執(zhí)行
  setTimeout(function() {
    console.log('This will not run');
  }, 0);
});

上面代碼在exit事件的回調(diào)函數(shù)里面,指定了一個下一輪事件循環(huán),所要執(zhí)行的操作。這是無效的,不會得到執(zhí)行。

beforeExit事件

beforeExit事件在Node清空了Event Loop以后,再沒有任何待處理的任務(wù)時觸發(fā)。正常情況下,如果沒有任何待處理的任務(wù),Node進(jìn)程會自動退出,設(shè)置beforeExit事件的監(jiān)聽函數(shù)以后,就可以提供一個機(jī)會,再部署一些任務(wù),使得Node進(jìn)程不退出。

beforeExit事件與exit事件的主要區(qū)別是,beforeExit的監(jiān)聽函數(shù)可以部署異步任務(wù),而exit不行。

此外,如果是顯式終止程序(比如調(diào)用process.exit()),或者因為發(fā)生未捕獲的錯誤,而導(dǎo)致進(jìn)程退出,這些場合不會觸發(fā)beforeExit事件。因此,不能使用該事件替代exit事件。

uncaughtException事件

當(dāng)前進(jìn)程拋出一個沒有被捕捉的錯誤時,會觸發(fā)uncaughtException事件。

process.on('uncaughtException', function (err) {
  console.error('An uncaught error occurred!');
  console.error(err.stack);
});

部署uncaughtException事件的監(jiān)聽函數(shù),是免于node進(jìn)程終止的最后措施,否則node就要執(zhí)行process.exit()。出于除錯的目的,并不建議發(fā)生錯誤,還保持進(jìn)程運(yùn)行。

拋出錯誤之前部署的異步操作,還是會繼續(xù)執(zhí)行。只有完成以后,Node進(jìn)程才會退出。

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

setTimeout(function() {
  console.log('本行依然執(zhí)行');
}, 500);

// 下面的表達(dá)式拋出錯誤
nonexistentFunc();

上面代碼中,拋出錯誤之后,此前setTimeout指定的回調(diào)函數(shù)亦然會執(zhí)行。

信號事件

操作系統(tǒng)內(nèi)核向Node進(jìn)程發(fā)出信號,會觸發(fā)信號事件。實(shí)際開發(fā)中,主要對SIGTERM和SIGINT信號部署監(jiān)聽函數(shù),這兩個信號在非Windows平臺會導(dǎo)致進(jìn)程退出,但是只要部署了監(jiān)聽函數(shù),Node進(jìn)程收到信號后就不會退出。

// 讀取標(biāo)準(zhǔn)輸入,這主要是為了不讓當(dāng)前進(jìn)程退出
process.stdin.resume();

process.on('SIGINT', function() {
  console.log('SIGINT信號,按Control-D退出');
});

上面代碼部署了SIGINT信號的監(jiān)聽函數(shù),當(dāng)用戶按下Ctrl-C后,會顯示提示文字。

參考鏈接

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號