Node端異常捕獲的實(shí)現(xiàn)方法
常見Node報(bào)錯(cuò)處理機(jī)制
try catch
try...catch是大家最常用的錯(cuò)誤處理機(jī)制,Javascript語言內(nèi)置的錯(cuò)誤處理機(jī)制可以在檢測到代碼異常的時(shí)候直接進(jìn)行捕獲并處理。
function test() { try { throw new Error("error"); } catch(e) { console.log(e); } finally { console.log("finally"); } } test()
一般來說,throw 用于拋出異常,但是單純從語言的角度,我們可以拋出任何值,也不一定是異常邏輯,但是為了保證語義清晰,不建議用 throw 表達(dá)任何非異常邏輯。try 語句用于捕獲異常,用 throw 拋出的異常,可以在 try 語句的結(jié)構(gòu)中被處理掉:try 部分用于標(biāo)識(shí)捕獲異常的代碼段,catch 部分則用于捕獲異常后做一些處理,而 finally 則是用于執(zhí)行后做一些必須執(zhí)行的清理工作。catch 結(jié)構(gòu)會(huì)創(chuàng)建一個(gè)局部的作用域,并且把一個(gè)變量寫入其中,需要注意,在這個(gè)作用域,不能再聲明變量 e 了,否則會(huì)出錯(cuò)。在 catch 中重新拋出錯(cuò)誤的情況非常常見,在設(shè)計(jì)比較底層的函數(shù)時(shí),常常會(huì)這樣做,保證拋出的錯(cuò)誤能被理解。finally 語句一般用于釋放資源,它一定會(huì)被執(zhí)行,我們在前面的課程中已經(jīng)討論過一些 finally 的特征,即使在 try 中出現(xiàn)了 return,finally 中的語句也一定要被執(zhí)行。
Node原生錯(cuò)誤處理機(jī)制
大多數(shù)Node.js核心API都提供的是利用回調(diào)函數(shù)處理錯(cuò)誤,之所以采用這種錯(cuò)誤處理機(jī)制,是因?yàn)楫惒椒椒ㄋa(chǎn)生的方法并不能簡單地通過try...catch機(jī)制進(jìn)行攔截。
const fs = require('fs'); function read() { fs.readFile("/some/file/does-not-exist", (err, data) => { if(err) { throw new Error("file not exist"); } console.log(data); }); } read();
Promise
Promise是用于處理異步調(diào)用的規(guī)范,由于 JavaScript 特殊的 EventLoop 機(jī)制,由 Promise 異步產(chǎn)生錯(cuò)誤是沒有辦法使用 try...catch
的。
Promise提供的錯(cuò)誤處理機(jī)制,是通過catch方法進(jìn)行捕獲。
try { Promise.reject() } catch(err) { // 這里啥都 catch 不到 console.log(err) }
fs.copy( buildStatic, aresStatic ).then(() => { console.log(`${buildStatic} -> ${aresStatic}`) }).catch(err => { // 這里可以捕獲到報(bào)錯(cuò) console.log(err) })
async/await + try catch
async/await語法糖加上try...catch語句進(jìn)行的。這樣做的好處是異步和同步調(diào)用都能夠使用統(tǒng)一的方式進(jìn)行處理了。
對于異步代碼,建議統(tǒng)一轉(zhuǎn)換成Promise然后采用async/await + try...catch這種方式進(jìn)行處理。這樣風(fēng)格統(tǒng)一,程序的健壯性也大大加強(qiáng)。
async function one() { // a未定義 a.b = 3 } async function test() { try { await one(); } catch(error) { // a is not defined console.log(error); } } test();
unhandledRejection
實(shí)際開發(fā)中,總是會(huì)有一些 Promise 被遺漏掉catch處理,沒有得到錯(cuò)誤處理,會(huì)導(dǎo)致應(yīng)用crash。我們可以通過**unhandledrejection
** 事件捕獲未處理的 Promise 錯(cuò)誤。
實(shí)現(xiàn)原理:Node.js 會(huì)在每次 Tick 執(zhí)行完后檢查是否有未捕獲的錯(cuò)誤 Promise,如果有,則觸發(fā) unhandledRejection
事件。
process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at:', p, 'reason:', reason); });
特殊情況如何捕獲異常
如果是回調(diào)函數(shù)中捕獲異常怎么做?用domain去捕獲,domian捕獲會(huì)拋出500錯(cuò)誤,但是domain捕獲有一個(gè)問題,會(huì)丟失棧信息,無法保證程序健康進(jìn)行,所以要結(jié)束進(jìn)程,在回調(diào)函數(shù)中process.exit(1)
,然后用node的server.close方法再去釋放,server.close連接釋放后自動(dòng)結(jié)束進(jìn)程,所以不用在server.close中去結(jié)束進(jìn)程process.exit(1)
uncaughtExpection捕獲異常的的原理就是:uncaughtExpection事件存在回調(diào)函數(shù)process.on("uncaughtExpection",callback)
時(shí)node不會(huì)強(qiáng)制結(jié)束進(jìn)程,這樣可彌補(bǔ)domain丟失stack的問題
所以domian去捕獲絕大部分回調(diào)函數(shù)中的異常,uncaughtExpection去捕獲丟失stack異常,這樣就完整了
app.use(function(req,res,next){ var reqDomain = domain.create(); reqDomain.on("err",function(){ try { var killTimer = setTimeout(function(){ process.exit(1); },1000) killTimer.unref(); server.close(); res.send(500); } catch(e) { // statements console.log(e.stack); } }) reqDomain.run(next); }); process.on("uncaughtException",function(err){ console.log(err); try{ var killTimer = setTimeout(function(){ process.exit(1) },1000) killTimer.unref(); server.close(); }catch(e){ console.log(e.stack); } });
uncaughtException
uncaughtException
也是 NodeJS 進(jìn)程的一個(gè)事件。如果進(jìn)程里產(chǎn)生了一個(gè)異常而沒有被任何Try Catch
捕獲會(huì)觸發(fā)這個(gè)事件。
NodeJS 對于未捕獲異常的默認(rèn)處理是:
- 觸發(fā) uncaughtException
事件
- 如果 uncaughtException 沒有被監(jiān)聽
- 打印異常的堆棧信息
- 觸發(fā)進(jìn)程的 exit 事件
所以如果某個(gè)報(bào)錯(cuò)沒有被任意try catch捕獲,且沒有定義uncaughtException事件,就會(huì)導(dǎo)致程序退出。
process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason) })
Express錯(cuò)誤處理
Express中,路由或中間件報(bào)錯(cuò)處理可以通過特殊的中間件來完成。
一般中間件的參數(shù)為3個(gè):req
,res
, next
。如果你use
一個(gè)4個(gè)參數(shù)的中間件,它將被Express視為錯(cuò)誤處理中間件。
app.get('/a',function(req,res,next){ res.end('hahah'); next(new Error('錯(cuò)誤啦')); }); app.use('/a',function(err,req,res,next){ console.log('路由錯(cuò)誤'+err); }) //all error中間件 app.use(function(err, req, res, next) { console.log("Error happens", err.stack); }); //錯(cuò)誤傳遞,/a的錯(cuò)誤處理首先匹配/a那個(gè)錯(cuò)誤中間件,如果不用next就不會(huì)傳遞到全局錯(cuò)誤處理中間件 //如果在/a錯(cuò)誤處理中間件里調(diào)用next(err) 那么全局錯(cuò)誤中間件也會(huì)被執(zhí)行
到此這篇關(guān)于Node端異常捕獲的實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)Node 異常捕獲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用nodejs?+?koa?+?typescript?集成和自動(dòng)重啟的問題
這篇文章主要介紹了nodejs?+?koa?+?typescript?集成和自動(dòng)重啟,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12node將對象轉(zhuǎn)化為query的實(shí)現(xiàn)方法
本文主要介紹了node將對象轉(zhuǎn)化為query的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01詳解Node中導(dǎo)入模塊require和import的區(qū)別
本篇文章主要介紹了詳解Node中導(dǎo)入模塊require和import的區(qū)別,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-08-08node.js基于fs模塊對系統(tǒng)文件及目錄進(jìn)行讀寫操作的方法詳解
這篇文章主要介紹了node.js基于fs模塊對系統(tǒng)文件及目錄進(jìn)行讀寫操作的方法,結(jié)合實(shí)例形式分析了nodejs使用fs模塊針對文件與目錄的讀寫、創(chuàng)建、刪除等相關(guān)操作技巧,需要的朋友可以參考下2017-11-11Node.js中Koa2在控制臺(tái)輸出請求日志的方法示例
這篇文章主要給大家介紹了關(guān)于Node.js中Koa2在控制臺(tái)輸出請求日志的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Node.js具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05nodejs與瀏覽器中全局對象區(qū)別點(diǎn)總結(jié)
在本篇文章里小編給大家整理的是一篇關(guān)于nodejs與瀏覽器中全局對象區(qū)別點(diǎn)總結(jié)內(nèi)容,對此有需要的朋友們可以學(xué)習(xí)下。2021-12-12nodejs結(jié)合Socket.IO實(shí)現(xiàn)的即時(shí)通訊功能詳解
這篇文章主要介紹了nodejs結(jié)合Socket.IO實(shí)現(xiàn)的即時(shí)通訊功能,結(jié)合實(shí)例形式詳細(xì)分析了nodejs結(jié)合Socket.IO實(shí)現(xiàn)即時(shí)通訊的相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2018-01-01node.js中的events.emitter.listeners方法使用說明
這篇文章主要介紹了node.js中的events.emitter.listeners方法使用說明,本文介紹了events.emitter.listeners 的方法說明、語法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下2014-12-12基于Koa(nodejs框架)對json文件進(jìn)行增刪改查的示例代碼
這篇文章主要介紹了基于Koa(nodejs框架)對json文件進(jìn)行增刪改查的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02