ERROR簡介
Node.js 的錯誤分為四類:
- 標(biāo)準(zhǔn) JavaScript 錯誤,如
EvalError,SynctaxError,RangeError,ReferenceError,TypeError,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 時,如 Stream,Event 等模塊,調(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 可能處理的方式不同,使用的時候請查閱文檔
- Node.js ERROR 官方文檔。
- Node.js 文檔版本為: v8.9.1
簡書作者 小菜荔枝原創(chuàng) 轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)