Node.js ERROR 帶你快速理解 Node.js 的錯誤處理機(jī)制

ERROR簡介

Node.js 的錯誤分為四類:

  • 標(biāo)準(zhǔn) JavaScript 錯誤,如 EvalErrorSynctaxError,RangeError,ReferenceErrorTypeError,URIError
  • 系統(tǒng)錯誤,如通過程序我們想打開一個文件,但是系統(tǒng)中不存在這個文件,就會拋出系統(tǒng)錯誤
  • 通過程序代碼 throw() 拋出的錯誤
  • 斷言錯誤,通過模塊 assert 拋出的錯誤

同步API和異步API

Node.js的API主要有兩種風(fēng)格,同步和異步,如何區(qū)分呢,大部分異步API一般都有一個回調(diào)函數(shù) callback 作為其參數(shù),而大部分同步API則不會,例如:

// 異步 API
const fs = require('fs');
fs.readFile('/etc/passwd', (err, data) => {
  if (err) console.log(err);
  else console.log(data);
});

// 同步 API
fs.readFileSync('/etc/passwd');

Node.js 風(fēng)格的回調(diào)

Node.js 大部分的異步方法都接受一個回調(diào)函數(shù)作為參數(shù),我們通過該回調(diào)函數(shù)的第一個參數(shù)來判斷是否發(fā)生了錯誤,如果是 null,則沒有發(fā)生錯誤,如果不是 null,則調(diào)用該方法出現(xiàn)了錯誤,我們管這種回調(diào)叫做 Node.js 風(fēng)格的回調(diào)

const fs = require('fs');

fs.readFile('/some/file/that/does-not-exist', function(err, data){
  if (err) {
    console.error('There was an error', err);
    return;
  }
  console.log(data);
});

注意:如果想在異步方法的回調(diào)函數(shù)里面拋出錯誤,不要放在 try / catch 代碼塊中,這樣不僅不會捕獲到異常,而且未捕獲的異??赡軙斐沙绦蛲V?/strong>

// 這樣不會捕獲異常:
const fs = require('fs');

try {
  fs.readFile('/some/file/that/does-not-exist', (err, data) => {
    // mistaken assumption: throwing here...
    if (err) {
      throw err; // 拋出錯誤,但是無法被捕獲到
    }
  });
} catch (err) {
  // 無法被捕獲到
  console.error(err);
}

因回調(diào)函數(shù)還沒有執(zhí)行,try / catch 代碼已經(jīng)執(zhí)行完畢并退出,所以無法捕獲錯誤。如果想捕獲錯誤,可以使用 process.on('uncaughtException') (或者 Domain 模塊來處理,但 Domain 模塊已被新版本棄用,這里只是提一嘴,不推薦使用)方法來處理,可以把上面的代碼改造成:

const fs = require('fs');

fs.readFile('/some/file/that/does-not-exist', (err, data) => {
    // mistaken assumption: throwing here...
    if(err) {
        throw err; 
    }
});

process.on('uncaughtException', (err) => {
    console.log(err);
})

錯誤傳播和攔截

Node.js 支持多種機(jī)制來處理應(yīng)用程序運行時發(fā)生的錯誤。如何處理這些錯誤完全取決于錯誤的類型和被調(diào)用的 API 的風(fēng)格,所有的 JavaScript 錯誤和大部分同步 API 都用 try / catch 機(jī)制處理:

const fs = require('fs');
try {
  const m = 1;
  const n = m + z; // javaScript 錯誤
  fs.readFileSync('./test.js');  // 同步API
} catch (err) {
  // 在這處理錯誤
}

異步 API 分為兩種處理方式:一種是 Node.js 回調(diào)風(fēng)格的 API,前面已有介紹;另一種方式:如果一個對象是一個 EventEmitter 時,如 StreamEvent 等模塊,調(diào)用這個對象的異步方法時可以通過這個對象的 error 事件處理:

const net = require('net');
const connection = net.connect('localhost'); // EventEmitter

// 綁定 error 事件
connection.on('error', (err) => {
  // 處理 err
  console.error(err);
});

connection.pipe(process.stdout);

注意:如果不用 error 事件處理,我們的程序?qū)罎?/strong>,該錯誤也可以用 process.on('uncaughtException') 來捕獲

CLASS Error

Node.js 的錯誤機(jī)制不會解釋為什么會發(fā)生錯誤,它只會通過追蹤棧信息來盡可能的描述該錯誤

new Error(message)

創(chuàng)建一個 Error 實例,message 是個字符串,也可以是一個對象(如果是對象,則 Node.js 先會把這個對象轉(zhuǎn)化成字符串,再調(diào)用 new Error(message)

Error.captureStackTrace(targetObject[, constructorOpt])

targetObject 對象設(shè)置一個 stack 屬性,記錄 targetObject 的追蹤棧信息,constructorOpt是一個函數(shù),如果傳了該參數(shù),則該參數(shù)會在追蹤棧信息中隱藏:

function MyError() {
  Error.captureStackTrace(this, MyError); // MyError會在結(jié)果中隱藏
}
new MyError().stack;
Error.stackTraceLimit

追蹤棧信息的條數(shù),默認(rèn)值是 10,可以設(shè)置為其他值,如果設(shè)置的不是數(shù)字或者是負(fù)數(shù),則不會追蹤任何棧信息

Error Object
  • error.code 錯誤碼,參照 Node.js Error Codes
  • error.message 錯誤信息
  • error.stack 追蹤棧信息
try {
  Error.stackTraceLimit = 15;
  const m = z++;
} catch (e) {
  console.log(e.stack);
}
// ReferenceError: z is not defined
//   at Object.<anonymous> (C:\Users\papa_\.WebStorm2017.3\config\consoles\ide\ide-scripting.js:78:13)
//   at Module._compile (module.js:635:30)
//   at Object.Module._extensions..js (module.js:646:10)
//   at Module.load (module.js:554:32)
//   at tryModuleLoad (module.js:497:12)
//   at Function.Module._load (module.js:489:3)
//   at Function.Module.runMain (module.js:676:10)
//   at startup (bootstrap_node.js:187:16)
//   at bootstrap_node.js:608:3
  • C:\Users\papa_\.WebStorm2017.3\config\consoles\ide\ide-scripting.js:78:13 帶有有絕對路徑的一般表示用戶程序的調(diào)用
  • module.js:635:30 沒有絕對路徑的一般表示 Node.js 的調(diào)用
  • native 一個方法描述一般表示 V8 引擎的調(diào)用

結(jié)語:本文介紹了 Node.js 的錯誤異常處理機(jī)制,跟原生JS還是有很大的差別,合理的處理 ERROR 會使我們的程序更健壯也會讓開發(fā)人員更容易地確定問題并解決;原文檔中有關(guān)系統(tǒng)錯誤做了詳細(xì)的說明,因為跟 linux 的系統(tǒng)錯誤類似,在這就不做解釋了;大部分異步同步 API 的處理方式都是與本文所述一致的的,但有一些特殊的 API 可能處理的方式不同,使用的時候請查閱文檔

簡書作者 小菜荔枝原創(chuàng) 轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • topics: 1.The Node.js philosophy 2.The reactor pattern 3....
    宮若石閱讀 1,245評論 0 1
  • # 模塊機(jī)制 node采用模塊化結(jié)構(gòu),按照CommonJS規(guī)范定義和使用模塊,模塊與文件是一一對應(yīng)關(guān)系,即加載一個...
    RichRand閱讀 2,747評論 0 3
  • 雖然我是個不折不扣的女漢子,可是聽當(dāng)我到那些靜靜流淌的曲調(diào)卻還是會突然變得沉默,會覺得很傷心,像是身在一條船上,...
    高卷卷咯閱讀 299評論 0 0
  • #過一個傳統(tǒng)年#幼兒園的時候我就知道元宵節(jié)要吃月餅(難道不是湯圓么)和做燈籠了,過年前,我在c+和小朋友們每個人都...
    bdc031d36324閱讀 352評論 0 0
  • 今天是14號啦~大貓已經(jīng)從太原回來兩天了。將近三個多月沒有見吧,可是回來到我身邊的時候自然而熟悉。我想,他或者就是...
    余暖Ti閱讀 375評論 1 0

友情鏈接更多精彩內(nèi)容