process對象是Node的一個全局對象,提供當前node進程的信息。它可以在腳本的任意位置使用,不必通過require命令加載。該對象部署了EventEmitter接口。
[TOC]
## 進程信息
通過process對象,可以獲知當前進程的很多信息。
### 退出碼
進程退出時,會返回一個整數值,表示退出時的狀態。這個整數值就叫做退出碼。下面是常見的Node進程退出碼。
* 0,正常退出
* 1,發生未捕獲錯誤
* 5,V8執行錯誤
* 8,不正確的參數
* 128 + 信號值,如果Node接受到退出信號(比如SIGKILL或SIGHUP),它的退出碼就是128加上信號值。由于128的二進制形式是10000000, 所以退出碼的后七位就是信號值。
## 屬性
process對象提供一系列屬性,用于返回系統信息。
* process.argv:返回當前進程的命令行參數數組。
* process.env:返回一個對象,成員為當前shell的環境變量,比如process.env.HOME。
* process.installPrefix:node的安裝路徑的前綴,比如`/usr/local`,則node的執行文件目錄為`/usr/local/bin/node`。
* process.pid:當前進程的進程號。
* process.platform:當前系統平臺,比如Linux。
* process.title:默認值為“node”,可以自定義該值。
* process.version:Node的版本,比如v0.10.18。
下面是主要屬性的介紹。
### stdout,stdin,stderr
以下屬性指向系統IO。
(1)stdout
stdout屬性指向標準輸出(文件描述符1)。它的write方法等同于console.log,可用在標準輸出向用戶顯示內容。
~~~
console.log = function(d) {
process.stdout.write(d + '\n');
};
~~~
下面代碼表示將一個文件導向標準輸出。
~~~
var fs = require('fs');
fs.createReadStream('wow.txt')
.pipe(process.stdout);
~~~
上面代碼中,由于process.stdout和process.stdin與其他進程的通信,都是流(stream)形式,所以必須通過pipe管道命令中介。
~~~
var fs = require('fs');
var zlib = require('zlib');
fs.createReadStream('wow.txt')
.pipe(zlib.createGzip())
.pipe(process.stdout);
~~~
上面代碼通過pipe方法,先將文件數據壓縮,然后再導向標準輸出。
(2)stdin
stdin代表標準輸入(文件描述符0)。
~~~
process.stdin.pipe(process.stdout)
~~~
上面代碼表示將標準輸入導向標準輸出。
由于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屬性指向標準錯誤(文件描述符2)。
### argv,execPath,execArgv
argv屬性返回一個數組,由命令行執行腳本時的各個參數組成。它的第一個成員總是node,第二個成員是腳本文件名,其余成員是腳本文件的參數。
請看下面的例子,新建一個腳本文件argv.js。
~~~
// argv.js
console.log("argv: ",process.argv);
~~~
在命令行下調用這個腳本,會得到以下結果。
~~~
$ node argv.js a b c
[ 'node', '/path/to/argv.js', 'a', 'b', 'c' ]
~~~
上面代碼表示,argv返回數組的成員依次是命令行的各個部分,真正的參數實際上是從`process.argv[2]`開始。要得到真正的參數部分,可以把argv.js改寫成下面這樣。
~~~
// argv.js
var myArgs = process.argv.slice(2);
console.log(myArgs);
~~~
execPath屬性返回執行當前腳本的Node二進制文件的絕對路徑。
~~~
> process.execPath
'/usr/local/bin/node'
>
~~~
execArgv屬性返回一個數組,成員是命令行下執行腳本時,在Node可執行文件與腳本文件之間的命令行參數。
~~~
# script.js的代碼為
# console.log(process.execArgv);
$ node --harmony script.js --version
~~~
## 方法
process對象提供以下方法:
* process.chdir():切換工作目錄到指定目錄。
* process.cwd():返回運行當前腳本的工作目錄的路徑。
* process.exit():退出當前進程。
* process.getgid():返回當前進程的組ID(數值)。
* process.getuid():返回當前進程的用戶ID(數值)。
* process.nextTick():指定回調函數在當前執行棧的尾部、下一次Event Loop之前執行。
* process.on():監聽事件。
* process.setgid():指定當前進程的組,可以使用數字ID,也可以使用字符串ID。
* process.setuid():指定當前進程的用戶,可以使用數字ID,也可以使用字符串ID。
### process.cwd(),process.chdir()
cwd方法返回進程的當前目錄,chdir方法用來切換目錄。
~~~
> process.cwd()
'/home/aaa'
> process.chdir('/home/bbb')
> process.cwd()
'/home/bbb'
~~~
## process.nextTick()
process.nextTick()將任務放到當前執行棧的尾部。
~~~
process.nextTick(function () {
console.log('下一次Event Loop即將開始!');
});
~~~
上面代碼可以用`setTimeout(f,0)`改寫,效果接近,但是原理不同。`setTimeout(f,0)`是將任務放到當前任務隊列的尾部,在下一次Event Loop時執行。另外,nextTick的效率更高,因為不用檢查是否到了指定時間。
~~~
setTimeout(function () {
console.log('已經到了下一輪Event Loop!');
}, 0)
~~~
### process.exit()
process.exit方法用來退出當前進程,它可以接受一個數值參數。如果參數大于0,表示執行失敗;如果等于0表示執行成功。
~~~
if (err) {
process.exit(1);
} else {
process.exit(0);
}
~~~
process.exit()執行時,會觸發exit事件。
### process.on()
process.on方法用來監聽各種事件,并指定回調函數。
~~~
process.on('uncaughtException', function(err){
console.log('got an error: %s', err.message);
process.exit(1);
});
setTimeout(function(){
throw new Error('fail');
}, 100);
~~~
上面代碼是process監聽Node的一個全局性事件uncaughtException,只要有錯誤沒有捕獲,就會觸發這個事件。
process支持的事件有以下一些。
* data事件:數據輸出輸入時觸發
* SIGINT事件:接收到系統信號時觸發
~~~
process.on('SIGINT', function () {
console.log('Got a SIGINT. Goodbye cruel world');
process.exit(0);
});
~~~
使用時,向該進程發出系統信號,就會導致進程退出。
~~~
$ kill -s SIGINT [process_id]
~~~
SIGTERM信號表示內核要求當前進程停止,進程可以自行停止,也可以忽略這個信號。
~~~
var http = require('http');
var server = http.createServer(function (req, res) {
});
process.on('SIGTERM', function () {
server.close(function () {
process.exit(0);
});
});
~~~
上面代碼表示,進程接到SIGTERM信號之后,關閉服務器,然后退出進程。需要注意的是,這時進程不會馬上退出,而是要回應完最后一個請求,處理完所有回調函數,然后再退出。
### process.kill()
process.kill方法用來對指定ID的線程發送信號,默認為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毫秒后向當前進程發送SIGTERM信號(終結進程),因此1000毫秒后的指定事件不會被觸發。
## 事件
### exit事件
當前進程退出時,會觸發exit事件,可以對該事件指定回調函數。
~~~
process.on('exit', function () {
fs.writeFileSync('/tmp/myfile', '需要保存到硬盤的信息');
});
~~~
注意,此時回調函數只能執行同步操作,不能包含異步操作,因為執行完回調函數,進程就會退出,無法監聽到回調函數的操作結果。
~~~
process.on('exit', function(code) {
// 不會執行
setTimeout(function() {
console.log('This will not run');
}, 0);
});
~~~
上面代碼在exit事件的回調函數里面,指定了一個下一輪事件循環,所要執行的操作。這是無效的,不會得到執行。
### beforeExit事件
beforeExit事件在Node清空了Event Loop以后,再沒有任何待處理的任務時觸發。正常情況下,如果沒有任何待處理的任務,Node進程會自動退出,設置beforeExit事件的監聽函數以后,就可以提供一個機會,再部署一些任務,使得Node進程不退出。
beforeExit事件與exit事件的主要區別是,beforeExit的監聽函數可以部署異步任務,而exit不行。
此外,如果是顯式終止程序(比如調用process.exit()),或者因為發生未捕獲的錯誤,而導致進程退出,這些場合不會觸發beforeExit事件。因此,不能使用該事件替代exit事件。
### uncaughtException事件
當前進程拋出一個沒有被捕捉的錯誤時,會觸發uncaughtException事件。
~~~
process.on('uncaughtException', function (err) {
console.error('An uncaught error occurred!');
console.error(err.stack);
});
~~~
部署uncaughtException事件的監聽函數,是免于node進程終止的最后措施,否則node就要執行`process.exit()`。出于除錯的目的,并不建議發生錯誤,還保持進程運行。
拋出錯誤之前部署的異步操作,還是會繼續執行。只有完成以后,Node進程才會退出。
~~~
process.on('uncaughtException', function(err) {
console.log('Caught exception: ' + err);
});
setTimeout(function() {
console.log('本行依然執行');
}, 500);
// 下面的表達式拋出錯誤
nonexistentFunc();
~~~
上面代碼中,拋出錯誤之后,此前setTimeout指定的回調函數亦然會執行。
### 信號事件
操作系統內核向Node進程發出信號,會觸發信號事件。實際開發中,主要對SIGTERM和SIGINT信號部署監聽函數,這兩個信號在非Windows平臺會導致進程退出,但是只要部署了監聽函數,Node進程收到信號后就不會退出。
~~~
// 讀取標準輸入,這主要是為了不讓當前進程退出
process.stdin.resume();
process.on('SIGINT', function() {
console.log('SIGINT信號,按Control-D退出');
});
~~~
上面代碼部署了SIGINT信號的監聽函數,當用戶按下Ctrl-C后,會顯示提示文字。
## 參考鏈接
* José F. Romaniello,?[Graceful shutdown in node.js](http://joseoncode.com/2014/07/21/graceful-shutdown-in-node-dot-js/)
- 第一章 導論
- 1.1 前言
- 1.2 為什么學習JavaScript?
- 1.3 JavaScript的歷史
- 第二章 基本語法
- 2.1 語法概述
- 2.2 數值
- 2.3 字符串
- 2.4 對象
- 2.5 數組
- 2.6 函數
- 2.7 運算符
- 2.8 數據類型轉換
- 2.9 錯誤處理機制
- 2.10 JavaScript 編程風格
- 第三章 標準庫
- 3.1 Object對象
- 3.2 Array 對象
- 3.3 包裝對象和Boolean對象
- 3.4 Number對象
- 3.5 String對象
- 3.6 Math對象
- 3.7 Date對象
- 3.8 RegExp對象
- 3.9 JSON對象
- 3.10 ArrayBuffer:類型化數組
- 第四章 面向對象編程
- 4.1 概述
- 4.2 封裝
- 4.3 繼承
- 4.4 模塊化編程
- 第五章 DOM
- 5.1 Node節點
- 5.2 document節點
- 5.3 Element對象
- 5.4 Text節點和DocumentFragment節點
- 5.5 Event對象
- 5.6 CSS操作
- 5.7 Mutation Observer
- 第六章 瀏覽器對象
- 6.1 瀏覽器的JavaScript引擎
- 6.2 定時器
- 6.3 window對象
- 6.4 history對象
- 6.5 Ajax
- 6.6 同域限制和window.postMessage方法
- 6.7 Web Storage:瀏覽器端數據儲存機制
- 6.8 IndexedDB:瀏覽器端數據庫
- 6.9 Web Notifications API
- 6.10 Performance API
- 6.11 移動設備API
- 第七章 HTML網頁的API
- 7.1 HTML網頁元素
- 7.2 Canvas API
- 7.3 SVG 圖像
- 7.4 表單
- 7.5 文件和二進制數據的操作
- 7.6 Web Worker
- 7.7 SSE:服務器發送事件
- 7.8 Page Visibility API
- 7.9 Fullscreen API:全屏操作
- 7.10 Web Speech
- 7.11 requestAnimationFrame
- 7.12 WebSocket
- 7.13 WebRTC
- 7.14 Web Components
- 第八章 開發工具
- 8.1 console對象
- 8.2 PhantomJS
- 8.3 Bower:客戶端庫管理工具
- 8.4 Grunt:任務自動管理工具
- 8.5 Gulp:任務自動管理工具
- 8.6 Browserify:瀏覽器加載Node.js模塊
- 8.7 RequireJS和AMD規范
- 8.8 Source Map
- 8.9 JavaScript 程序測試
- 第九章 JavaScript高級語法
- 9.1 Promise對象
- 9.2 有限狀態機
- 9.3 MVC框架與Backbone.js
- 9.4 嚴格模式
- 9.5 ECMAScript 6 介紹
- 附錄
- 10.1 JavaScript API列表
- 草稿一:函數庫
- 11.1 Underscore.js
- 11.2 Modernizr
- 11.3 Datejs
- 11.4 D3.js
- 11.5 設計模式
- 11.6 排序算法
- 草稿二:jQuery
- 12.1 jQuery概述
- 12.2 jQuery工具方法
- 12.3 jQuery插件開發
- 12.4 jQuery.Deferred對象
- 12.5 如何做到 jQuery-free?
- 草稿三:Node.js
- 13.1 Node.js 概述
- 13.2 CommonJS規范
- 13.3 package.json文件
- 13.4 npm模塊管理器
- 13.5 fs 模塊
- 13.6 Path模塊
- 13.7 process對象
- 13.8 Buffer對象
- 13.9 Events模塊
- 13.10 stream接口
- 13.11 Child Process模塊
- 13.12 Http模塊
- 13.13 assert 模塊
- 13.14 Cluster模塊
- 13.15 os模塊
- 13.16 Net模塊和DNS模塊
- 13.17 Express框架
- 13.18 Koa 框架