您好,登錄后才能下訂單哦!
小編給大家分享一下NodeJS處理Express中異步錯誤的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
Express 內置的異步錯誤處理
在默認情況下,Express 會捕獲所有在路由處理函數中的拋出的異常,然后將它傳給下一個錯誤處理中間件:
app.get('/', function (req, res) { throw new Error('oh no!') }) app.use(function (err, req, res, next) { console.log(err.message) // 噢!不! })
對于同步執行的代碼,以上的處理已經足夠簡單。然而,當異步程序在執行時拋出異常的情況,Express 就無能為力。原因在于當你的程序開始執行回調函數時,它原來的棧信息已經丟失。
app.get('/', function (req, res) { queryDb(function (er, data) { if (er) throw er }) }) app.use(function (err, req, res, next) { // 這里拿不到錯誤信息 })
對于這種情況,可以使用 next 函數來將錯誤傳遞給下一個錯誤處理中間件
app.get('/', function (req, res, next) { queryDb(function (err, data) { if (err) return next(err) // 處理數據 makeCsv(data, function (err, csv) { if (err) return next(err) // 處理 csv }) }) }) app.use(function (err, req, res, next) { // 處理錯誤 })
使用這種方法雖然一時爽,卻帶來了兩個問題:
你需要顯式地在錯誤處理中間件中分別處理不同的異常。
一些隱式異常并沒有被處理(如嘗試獲取一個對象并不存在的屬性)
利用 Promise 傳遞異步錯誤
在異步執行的程序中使用 Promise 處理任何顯式或隱式的異常情況,只需要在 Promise 鏈尾加上 .catch(next) 即可。
app.get('/', function (req, res, next) { // do some sync stuff queryDb() .then(function (data) { // 處理數據 return makeCsv(data) }) .then(function (csv) { // 處理 csv }) .catch(next) }) app.use(function (err, req, res, next) { // 處理錯誤 })
現在,所有異步和同步程序都將被傳遞到錯誤處理中間件。棒棒的。
雖然 Promise 讓異步錯誤的傳遞變得容易,但這樣的代碼仍然有一些冗長和刻板。這時候 promise generator 就派上了用場。
用 Generators 簡化代碼
如果你使用的環境原生支持 Generators,你可以手動實現以下的功能。不過這里我們將借用 Bluebird.coroutine 來說明如何使用 Promise generator 來簡化剛才的代碼。
盡管接下來的例子使用的是 bluebird ,其它 Promise 庫(如 co)也都支持 Promise generator.
首先,我們需要使得 Express 路由函數與 Promise generator 兼容:
var Promise = require('bluebird') function wrap (genFn) { // 1 var cr = Promise.coroutine(genFn) // 2 return function (req, res, next) { // 3 cr(req, res, next).catch(next) // 4 } }
這個函數是一個高階函數,它做了以下幾件事情:(分別與代碼片段中的注釋對應)
以 Genrator 為唯一的輸入
讓這個函數懂得如何 yield promise
返回一個普通的 Express 路由函數
當這個函數被執行時,它會使用 coroutine 來 yield promise,捕獲期間發生的異常,然后將其傳遞給 next 函數
借助這個函數,我們就可以這樣構造路由函數:
app.get('/', wrap(function *(req, res) { var data = yield queryDb() // 處理數據 var csv = yield makeCsv(data) // 處理 csv })) app.use(function (err, req, res, next) { // 處理錯誤 })
現在,Express 的異步錯誤處理流程的可讀性已經近乎令人滿意,而且你可以像寫同步執行的代碼一樣去書寫異步執行的代碼,唯一不要忘了的就是 yield promises。
然而這還不是終點,ES7 的 async/await 提議可以讓代碼變得更簡潔。
使用 ES7 async/await
ES7 async/await 的行為就像 Promise Generator 一樣,只不過它可以被用到更多的地方(如類方法或者胖箭頭函數)。
為了在 Express 中使用 async/await,同時優雅地處理異步錯誤,我們仍然需要一個與上文提到的 wrap 類似的函數:
let wrap = fn => (...args) => fn(...args).catch(args[2])
這樣,我們就可以按底下這種方式書寫路由函數:
app.get('/', wrap(async function (req, res) { let data = await queryDb() // 處理數據 let csv = await makeCsv(data) // 處理 csv }))
現在可以愉快地寫代碼了
有了對同步和異步錯誤的處理,你可以用新的方式來開發 Express App。但有兩點需要注意:
要習慣使用 throw ,它使得你的代碼目的明確,throw 會明確地將程序引到錯誤處理中間件,這對同步或異步的程序都是適用的。
遇到特殊情況,當你覺得有必要時,也可以自行 try/catch。
app.get('/', wrap(async (req, res) => { if (!req.params.id) { throw new BadRequestError('Missing Id') } let companyLogo try { companyLogo = await getBase64Logo(req.params.id) } catch (err) { console.error(err) companyLogo = genericBase64Logo } }))
要習慣使用 custom error classes ,如 BadRequestError,因為這可以讓你在錯誤處理中間件中更方便地分類處理。
app.use(function (err, req, res, next) { if (err instanceof BadRequestError) { res.status(400) return res.send(err.message) } ... })
以上是“NodeJS處理Express中異步錯誤的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。