NodeJS異常處理uncaughtException篇

NodeJS異常處理uncaughtException篇

王龑 — APRIL 08, 2015express

不少 NodeJS 的開發者在抱怨異常處理太麻煩,咱們會經過一些列博客梳理一下NodeJS中常見的異常處理的手段。
和大多數編程語言同樣,在 NodeJS 裏能夠經過throw拋出一個異常:apache

throw new Error('Catch me');

爲了捕獲這個異常須要把代碼包在Try Catch中:編程

try{
    throw new Error('Catch me');
}catch(e){
    // error captured
}

然而,因爲 NodeJS 的異步特性,上述代碼只需稍加改造就會失效:服務器

try{
    process.nextTick(function my_app(){
        throw new Error('Catch me');
    })
}catch(e){
    // never called
}

在現實世界裏,異常老是會產生在某個模塊中。所謂模塊就是能完成一個功能的單元,即便是一個簡單的函數也能夠被看作一個模塊。隨着項目代碼行數增多,異步嵌套的複雜性增強,常常會有異常沒捕獲的狀況發生。一個沒有很強健壯性的 NodeJS 應用,會由於一個未捕獲的異常就整個掛掉,致使服務不可用。要改變你們以爲NodeJS是脆弱的這個認識,須要開發者加深對這門語言異常處理機制的瞭解。app

uncaughtException

uncaughtException 實際上是 NodeJS 進程的一個事件。若是進程裏產生了一個異常而沒有被任何Try Catch捕獲會觸發這個事件。爲了簡化問題,咱們仍是先看看同步狀況下的例子。異步

function external() {
    throw new Error('Catch me');
}

function internal() {
    external();
}

internal(); //error will be thrown

在命令行裏執行這個程序,腳本會在拋出異常的那一行中斷。接下來,因爲沒有Try Catch,異常會一直冒泡直到事件循環爲止,而NodeJS對異常的默認處理很是簡單,處理的代碼 相似 於:編程語言

function _MyFatalException(err){
    if(!process.emit('uncaughtException',err)){
        console.error(err.stack);
        process.emit('exit',1);
    }
}

NodeJS對於未捕獲異常的默認處理是: - 觸發 uncaughtException 事件 - 若是 uncaughtException 沒有被監聽,那麼 - 打印異常的堆棧信息 - 觸發進程的 exit 事件函數

若是你正在用 NodeJS 開發服務器,那麼你確定不但願偶然的一個異常讓整個服務器掛掉。那麼是否是隻要監聽了 uncaughtException 就能夠阻止服務器的進程退出呢? 答案是能夠,可是不要這麼作!。看這個例子:oop

var express = require('express');

function external(cb) {
    process.nextTick(function () {
        throw new Error();
        cb.call(null, 'sunny');
    })
}

var app = express();
app.get('/weather', function (req, res) {
    external(function (data) {
        res.end('Weather of Beijing is ' + data);
    })
})
app.listen(8018);


function noop(){}
process.on('uncaughtException', noop)

上面這個例子假設用戶訪問站點的時候能夠看到當地的天氣,咱們用 apache2-utils 來模擬請求ui

ab -n 1000 -c 20 http://localhost:8018/weather

糟糕!請求一直在等待,內存上漲。緣由在於res.end 永遠不會執行,現有的I/O處於等待的狀態,已經開闢的資源不只不會被釋放,並且服務器還在不知疲倦地接受新的用戶請求。

在 NodeJS 中處理異常是代價高昂的,並且一不當心就會致使內存泄露和讓應用程序處於不穩定的狀態。爲了提升健壯性,咱們能夠用Cluster模式,由之而來的推薦作法是: - 針對發生異常的請求返回一個錯誤代碼 - 出錯的Worker再也不接受新的請求 - 退出關閉Worker進程


本文做者系OneAPM工程師王龑 ,想閱讀更多好的技術文章,請訪問OneAPM官方技術博客。

相關文章
相關標籤/搜索