[譯]掌握Node.js的核心模塊-Process

[譯]掌握Node.js的核心模塊-Process

在這篇文章中,我們將學(xué)習(xí)Node.js的Process模塊以及模塊里隱藏的寶藏府怯。通讀本文后刻诊,你在編寫生產(chǎn)環(huán)境的應(yīng)用時(shí)會更加自信。你將了解Node.js應(yīng)用中Process的狀態(tài)牺丙、可以正常地關(guān)閉應(yīng)用以及更自信地處理錯(cuò)誤

在新的Mastering the Node.js Core Modules 系列中你可以學(xué)到核心模塊隱藏的或是幾乎無人知曉的特性则涯,以及如何去使用這些特性。過一遍Node.js模塊中基本要素冲簿,你會更加理解Node的運(yùn)行原理以及如何去處理錯(cuò)誤

在這個(gè)章節(jié)中粟判,我們會看一下Node.js的process模塊。這個(gè)process對象是EventEmitter的實(shí)例峦剔。它是一個(gè)全局變量浮入,在當(dāng)前的Node.js進(jìn)程中提供有關(guān)信息。

在 Node.js 的 process 模塊中需要注意的事件(Events)

因?yàn)?code>process模塊是EventEmitter的實(shí)例羊异,所以你像其他的EventEmitter的實(shí)例一樣用.on()方法來訂閱它的事件:

process.on('eventName', () => {
  //do something
})

uncaughtException

如果 Javascript 未捕獲的異常事秀,沿著代碼調(diào)用路徑反向傳遞回 Event loop,這個(gè)事件就會被觸發(fā)野舶。

默認(rèn)情況下易迹,如果沒有對uncaughtException事件添加任何監(jiān)聽器, Node.js 默認(rèn)情況下會將這些異常堆棧打印到stderr平道,然后進(jìn)程退出睹欲。 如果你添加了一個(gè)監(jiān)聽器就會覆蓋上述默認(rèn)行為

process.on('uncaughtException', (err) => {
  // here the 1 is a file descriptor for STDERR
  //這里的 l 是 STDERR 對應(yīng)的一個(gè)文件描述符
  fs.writeSync(1, `Caught exception: ${err}\n`)
})

在過去幾年中,我們見到很多對于這個(gè)事件的錯(cuò)誤的運(yùn)用一屋。當(dāng)使用這個(gè)process模塊中的uncaughtException事件時(shí)窘疮,有以下幾點(diǎn)十分重要的建議需要注意

  • 如果uncaughtException事件發(fā)生了,這表明你的應(yīng)用正處在一個(gè)未定義的狀態(tài)中
  • 十分不建議借助uncaughtException事件嘗試恢復(fù)應(yīng)用正常運(yùn)行冀墨,這種操作是不安全
  • 這個(gè)事件的處理器應(yīng)該只用來進(jìn)行已分配資源的同步清理操作(the handler should only be used for synchronous cleanup of allocated resources)
  • 如果處理這個(gè)事件的函數(shù)內(nèi)有異常拋出且未被捕獲的話闸衫,應(yīng)用會立刻退出
  • 你應(yīng)該使用外部工具來監(jiān)控你的進(jìn)程并且在必要時(shí)重啟它(比如當(dāng)它崩潰的時(shí)候)

unhandledRejection

如下示例代碼

const fs = require('fs-extra')

fs.copy('/tmp/myfile', '/tmp/mynewfile')
  .then(() => console.log('success!'))

如果需要復(fù)制的文件不存在的話會發(fā)生什么事?這個(gè)答案取決于你的Node.js的版本诽嘉,通常在4及4以下的版本中蔚出,進(jìn)程不會報(bào)錯(cuò)而是直接退出弟翘,留下坐在電腦前一臉懵逼的你。
而在最近的Node.js版本中骄酗,你會得到如下錯(cuò)誤提示

(node:28391) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): undefined
(node:28391) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

這段信息提示我們用來拷貝文件的promise中有個(gè)錯(cuò)誤沒有被捕獲稀余,正確的代碼應(yīng)該這么寫:

fs.copy('/tmp/myfile', '/tmp/mynewfile')
  .then(() => console.log('success!'))
  .catch(err => console.error(err))

Promise rejections未處理的問題其實(shí)跟uncaughtException一樣 - 你的 Node.js 進(jìn)程會處于一個(gè)未定義的狀態(tài),更糟糕的是趋翻,這可能會引起文件描述符未關(guān)閉( file descriptor failure )以及內(nèi)存泄漏睛琳。在這種情況下,你最好還是重新啟動Node.js進(jìn)程踏烙。

綜上所述掸掏,你應(yīng)該給unhandledRejection事件添加監(jiān)聽器并且使用process.exit(1)來退出進(jìn)程

推薦閱讀 Matteo Collina 的 make-promises-safe package,它可以解決你的困惑

Node.js 信號事件

當(dāng)Node.js進(jìn)程接收到一個(gè) POSIX 的信號時(shí),會觸發(fā)信號事件宙帝,接下來詳細(xì)闡述其中最重要的兩個(gè)丧凤,STGTERMSIGUSR1

點(diǎn)這里 可以找到所有的支持的信號

STGTERM

STGTERM信號會發(fā)送給Node進(jìn)程以請求終止進(jìn)程步脓。它與SIGKILL信號不同愿待,可以被監(jiān)聽或者無視

這樣可以通過釋放進(jìn)程分配的資源(比如文件描述符或者數(shù)據(jù)庫鏈接)來以很好的方式關(guān)閉進(jìn)程。這種關(guān)閉進(jìn)程的方式被稱為 graceful shutdown靴患。

事實(shí)上仍侥,在演繹一個(gè) graceful shutdown 之前必須經(jīng)歷以下這幾個(gè)步驟:

  1. 應(yīng)用收到了停止通知(收到SIGTERM信號)
  2. 應(yīng)用通知負(fù)載均衡器(load balancers)不要再處理新的請求
  3. 應(yīng)用完成所有正在進(jìn)行的請求
  4. 接下來,正確釋放所有的資源(像數(shù)據(jù)庫連接)
  5. 應(yīng)用用“成功”的狀態(tài)碼退出(process.exit()

閱讀這篇文章了解更多 graceful shutdown in Node.js

SIGUSR1

在 POSIX 的標(biāo)準(zhǔn)中鸳君, SIGUSR1SIGUSR2 是可以用在用戶定義的條件下农渊,Node.js 選擇用這個(gè)事件來啟動內(nèi)置的調(diào)試器

你可以用以下命令來給進(jìn)程發(fā)送SIGUSR1信號

kill -USR1 PID_OF_THE_NODE_JS_PROCESS

一旦你這么做了,所涉及到的Node進(jìn)程會讓你知道調(diào)試器正在運(yùn)行

Starting debugger agent.
Debugger listening on [::]:5858

Process 模塊公開的方法和值

process.cwd()

這個(gè)方法返回Node進(jìn)程的當(dāng)前工作目錄(絕對路徑)

$ node -e 'console.log(`Current directory: ${process.cwd()}`)'
Current directory: /Users/gergelyke/Development/risingstack/risingsite_v2

如果你想改變它或颊,可以調(diào)用process.chdir(path)這個(gè)方法

process.env

該屬性返回一個(gè)包含用戶環(huán)境的對象砸紊,就像 environ

如果你在根據(jù)十二要素應(yīng)用宣言(the 12-factor application principles)來構(gòu)建應(yīng)用程序,你會十分依賴它囱挑;就像 third principle of a twelve-factor application中說的:all configurations should be stored in the user environment 醉顽。

環(huán)境變量應(yīng)該是首選,因?yàn)檫@樣就可以在不更改代碼的前提下輕松更改不同的部署環(huán)境平挑。不像配置文件(config files)游添,它們基本不可能影響到代碼庫

值得一提的是,你可以更改process.env中的值通熄,雖然它不會反映到用戶環(huán)境中去

process.exit([code])

這個(gè)方法告訴 Node進(jìn)程用一個(gè)退出的狀態(tài)碼來同步地終止進(jìn)程唆涝,這么會有一些很重要的后果:

  • 它會強(qiáng)制讓進(jìn)程盡快終止
    • 哪怕有些異步操作仍然在進(jìn)行
    • 因?yàn)?code>STDOUT和STDERR的輸出的異步的,所以有些日志信息可能會丟失
  • 在大多數(shù)情況下唇辨,不推薦使用process.exit() - 你可以讓代碼運(yùn)行完畢自動退出作為替代

process.kill(pid, [signal])

你可以用這個(gè)方法來發(fā)送各種 POSIX 信號給各種進(jìn)程廊酣。你不僅僅可以像它名字寫的那樣用來殺死進(jìn)程。這個(gè)命令就像一個(gè)信號發(fā)送器(包括殺死系統(tǒng)調(diào)用)

Node.js 使用的退出代碼

如果一切正常助泽,Node.js 會用退出碼 0來退出啰扛。如果進(jìn)程因?yàn)槟撤N錯(cuò)誤而退出,你將會獲得以下狀態(tài)碼中的一種:

  • 1: 沒有被uncaughtException事件的監(jiān)聽器處理的致命異常
  • 5: V8中的致命錯(cuò)誤(比如分配內(nèi)存失斘撕亍)
  • 9:無效的參數(shù)隐解,比如指定了未知的選項(xiàng)或者一個(gè)選項(xiàng)引用了一個(gè)未設(shè)定的值

這些只是比較常見的退出碼,想看所有的狀態(tài)碼诫睬,請看 https://nodejs.org/api/process.html#process_exit_codes

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末煞茫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子摄凡,更是在濱河造成了極大的恐慌续徽,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亲澡,死亡現(xiàn)場離奇詭異钦扭,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)床绪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進(jìn)店門客情,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人癞己,你說我怎么就攤上這事膀斋。” “怎么了痹雅?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵仰担,是天一觀的道長。 經(jīng)常有香客問我绩社,道長摔蓝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任愉耙,我火速辦了婚禮项鬼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘劲阎。我一直安慰自己绘盟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布悯仙。 她就那樣靜靜地躺著龄毡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪锡垄。 梳的紋絲不亂的頭發(fā)上沦零,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天,我揣著相機(jī)與錄音货岭,去河邊找鬼路操。 笑死疾渴,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的屯仗。 我是一名探鬼主播搞坝,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼魁袜!你這毒婦竟也來了桩撮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤峰弹,失蹤者是張志新(化名)和其女友劉穎店量,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鞠呈,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡融师,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蚁吝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诬滩。...
    茶點(diǎn)故事閱讀 40,567評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖灭将,靈堂內(nèi)的尸體忽然破棺而出疼鸟,到底是詐尸還是另有隱情,我是刑警寧澤庙曙,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布空镜,位于F島的核電站,受9級特大地震影響捌朴,放射性物質(zhì)發(fā)生泄漏吴攒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一砂蔽、第九天 我趴在偏房一處隱蔽的房頂上張望洼怔。 院中可真熱鬧,春花似錦左驾、人聲如沸镣隶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽安岂。三九已至,卻和暖如春帆吻,著一層夾襖步出監(jiān)牢的瞬間域那,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工猜煮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留次员,地道東北人败许。 一個(gè)月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像淑蔚,于是被迫代替她去往敵國和親市殷。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評論 2 359

推薦閱讀更多精彩內(nèi)容