最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

NodeJS處理Express中異步錯誤

 更新時間:2017年03月26日 17:46:57   投稿:hebedich  
本文主要闡述如何在 Express 中使用錯誤處理中間件(error-handling middleware)來高效處理異步錯誤。在 Github 上有對應(yīng) 代碼實(shí)例 可供參考。

摘要

比起回調(diào)函數(shù),使用 Promise 來處理異步錯誤要顯得優(yōu)雅許多。

結(jié)合 Express 內(nèi)置的錯誤處理機(jī)制和 Promise 極大地降低產(chǎn)生未捕獲錯誤(uncaught exception)的可能性。

Promise 在ES6中是默認(rèn)選項。如果使用 Babel 轉(zhuǎn)譯,它也可以與 Generators 或者 Async/Await 相結(jié)合。

本文主要闡述如何在 Express 中使用錯誤處理中間件(error-handling middleware)來高效處理異步錯誤。在 Github 上有對應(yīng) 代碼實(shí)例 可供參考。

首先,讓我們一起了解 Express 提供的開箱即用的錯誤處理工具。然后,我們將探討如何使用 Promise, Generators 以及 ES7 的 async/await 來簡化錯誤處理流程。

Express 內(nèi)置的異步錯誤處理

在默認(rèn)情況下,Express 會捕獲所有在路由處理函數(shù)中的拋出的異常,然后將它傳給下一個錯誤處理中間件:

app.get('/', function (req, res) {
 throw new Error('oh no!')
})
app.use(function (err, req, res, next) {
 console.log(err.message) // 噢!不!
})

對于同步執(zhí)行的代碼,以上的處理已經(jīng)足夠簡單。然而,當(dāng)異步程序在執(zhí)行時拋出異常的情況,Express 就無能為力。原因在于當(dāng)你的程序開始執(zhí)行回調(diào)函數(shù)時,它原來的棧信息已經(jīng)丟失。

app.get('/', function (req, res) {
 queryDb(function (er, data) {
  if (er) throw er
 })
})
app.use(function (err, req, res, next) {
 // 這里拿不到錯誤信息
})

對于這種情況,可以使用 next 函數(shù)來將錯誤傳遞給下一個錯誤處理中間件

app.get('/', function (req, res, next) {
 queryDb(function (err, data) {
  if (err) return next(err)
  // 處理數(shù)據(jù)

  makeCsv(data, function (err, csv) {
   if (err) return next(err)
   // 處理 csv

  })
 })
})
app.use(function (err, req, res, next) {
 // 處理錯誤
})

使用這種方法雖然一時爽,卻帶來了兩個問題:

你需要顯式地在錯誤處理中間件中分別處理不同的異常。

一些隱式異常并沒有被處理(如嘗試獲取一個對象并不存在的屬性)

利用 Promise 傳遞異步錯誤

在異步執(zhí)行的程序中使用 Promise 處理任何顯式或隱式的異常情況,只需要在 Promise 鏈尾加上 .catch(next) 即可。

app.get('/', function (req, res, next) {
 // do some sync stuff
 queryDb()
  .then(function (data) {
   // 處理數(shù)據(jù)
   return makeCsv(data)
  })
  .then(function (csv) {
   // 處理 csv
  })
  .catch(next)
})
app.use(function (err, req, res, next) {
 // 處理錯誤
})

現(xiàn)在,所有異步和同步程序都將被傳遞到錯誤處理中間件。棒棒的。

雖然 Promise 讓異步錯誤的傳遞變得容易,但這樣的代碼仍然有一些冗長和刻板。這時候 promise generator 就派上了用場。

用 Generators 簡化代碼

如果你使用的環(huán)境原生支持 Generators,你可以手動實(shí)現(xiàn)以下的功能。不過這里我們將借用 Bluebird.coroutine 來說明如何使用 Promise generator 來簡化剛才的代碼。

盡管接下來的例子使用的是 bluebird ,其它 Promise 庫(如 co)也都支持 Promise generator.

首先,我們需要使得 Express 路由函數(shù)與 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
  }
}

這個函數(shù)是一個高階函數(shù),它做了以下幾件事情:(分別與代碼片段中的注釋對應(yīng))

以 Genrator 為唯一的輸入

讓這個函數(shù)懂得如何 yield promise

返回一個普通的 Express 路由函數(shù)

當(dāng)這個函數(shù)被執(zhí)行時,它會使用 coroutine 來 yield promise,捕獲期間發(fā)生的異常,然后將其傳遞給 next 函數(shù)

借助這個函數(shù),我們就可以這樣構(gòu)造路由函數(shù):

app.get('/', wrap(function *(req, res) {
 var data = yield queryDb()
 // 處理數(shù)據(jù)
 var csv = yield makeCsv(data)
 // 處理 csv
}))
app.use(function (err, req, res, next) {
 // 處理錯誤
})

現(xiàn)在,Express 的異步錯誤處理流程的可讀性已經(jīng)近乎令人滿意,而且你可以像寫同步執(zhí)行的代碼一樣去書寫異步執(zhí)行的代碼,唯一不要忘了的就是 yield promises。

然而這還不是終點(diǎn),ES7 的 async/await 提議可以讓代碼變得更簡潔。

使用 ES7 async/await

ES7 async/await 的行為就像 Promise Generator 一樣,只不過它可以被用到更多的地方(如類方法或者胖箭頭函數(shù))。

為了在 Express 中使用 async/await,同時優(yōu)雅地處理異步錯誤,我們?nèi)匀恍枰粋€與上文提到的 wrap 類似的函數(shù):

let wrap = fn => (...args) => fn(...args).catch(args[2])
這樣,我們就可以按底下這種方式書寫路由函數(shù):

app.get('/', wrap(async function (req, res) {
 let data = await queryDb()
 // 處理數(shù)據(jù)
 let csv = await makeCsv(data)
 // 處理 csv
}))

現(xiàn)在可以愉快地寫代碼了

有了對同步和異步錯誤的處理,你可以用新的方式來開發(fā) Express App。但有兩點(diǎn)需要注意:

要習(xí)慣使用 throw ,它使得你的代碼目的明確,throw 會明確地將程序引到錯誤處理中間件,這對同步或異步的程序都是適用的。
遇到特殊情況,當(dāng)你覺得有必要時,也可以自行 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
   }
  }))

要習(xí)慣使用 custom error classes ,如 BadRequestError,因?yàn)檫@可以讓你在錯誤處理中間件中更方便地分類處理。

app.use(function (err, req, res, next) {
   if (err instanceof BadRequestError) {
    res.status(400)
    return res.send(err.message)
   }
   ...
  })

需要注意

  1. 以上介紹的方法要求所有異步操作必須返回 promise。如果你的異步操作是使用回調(diào)函數(shù)的方式,你需要將其轉(zhuǎn)化成 promise。(可以直接使用 Bluebird.promisifyAll 這類函數(shù))
  2. 事件發(fā)射器(如 steams)仍然會導(dǎo)致未捕獲異常,你需要注意合理地處理這類情況:

相關(guān)文章

  • Node.js學(xué)習(xí)之地址解析模塊URL的使用詳解

    Node.js學(xué)習(xí)之地址解析模塊URL的使用詳解

    url模塊是nodejs里面的一個簡單的模塊,下面這篇文章主要給大家介紹了關(guān)于Node.js學(xué)習(xí)之地址解析模塊URL使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-09-09
  • Node.js實(shí)現(xiàn)http請求服務(wù)與Mysql數(shù)據(jù)庫操作方法詳解

    Node.js實(shí)現(xiàn)http請求服務(wù)與Mysql數(shù)據(jù)庫操作方法詳解

    這篇文章主要介紹了Node.js實(shí)現(xiàn)http請求服務(wù)與Mysql數(shù)據(jù)庫操作方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-10-10
  • Node使用Nodemailer發(fā)送郵件的方法實(shí)現(xiàn)

    Node使用Nodemailer發(fā)送郵件的方法實(shí)現(xiàn)

    這篇文章主要介紹了Node使用Nodemailer發(fā)送郵件的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • 使用nodeJS中的fs模塊對文件及目錄進(jìn)行讀寫,刪除,追加,等操作詳解

    使用nodeJS中的fs模塊對文件及目錄進(jìn)行讀寫,刪除,追加,等操作詳解

    nodeJS中fs模塊對系統(tǒng)文件及目錄進(jìn)行讀寫操作,本文將詳細(xì)介紹nodejs中的文件操作模塊fs的使用方法
    2020-02-02
  • node+koa+canvas繪制出貨單、收據(jù)票據(jù)的方法

    node+koa+canvas繪制出貨單、收據(jù)票據(jù)的方法

    在生成票據(jù)需求中,我們會想到前端生成或者后端生成返回圖片地址訪問兩個方法,前端生成則不需要調(diào)用接口,而后端是在完成整個流程時就進(jìn)行生成然后把上傳的地址保存數(shù)據(jù)庫,這篇文章主要介紹了node+koa+canvas繪制出貨單,收據(jù),票據(jù),需要的朋友可以參考下
    2022-09-09
  • WebSocket Node構(gòu)建HTTP隧道實(shí)現(xiàn)實(shí)例

    WebSocket Node構(gòu)建HTTP隧道實(shí)現(xiàn)實(shí)例

    這篇文章主要為大家介紹了WebSocket Node構(gòu)建HTTP隧道實(shí)現(xiàn)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Node.js?應(yīng)用探索文件解壓縮示例詳解

    Node.js?應(yīng)用探索文件解壓縮示例詳解

    這篇文章主要為大家介紹了Node.js?應(yīng)用探索文件解壓縮示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Node.js應(yīng)用程序遇到了內(nèi)存溢出的問題解決方案

    Node.js應(yīng)用程序遇到了內(nèi)存溢出的問題解決方案

    文章介紹了Node.js應(yīng)用程序內(nèi)存溢出的原因,包括內(nèi)存泄漏、大型數(shù)據(jù)集處理、無限循環(huán)或遞歸、并發(fā)問題和外部內(nèi)存分配,文章還提供了優(yōu)化代碼、分批處理數(shù)據(jù)和增加內(nèi)存限制的解決方案,感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • 使用Node實(shí)現(xiàn)Git倉庫批量克隆的操作步驟

    使用Node實(shí)現(xiàn)Git倉庫批量克隆的操作步驟

    分享一個node腳本,通過調(diào)用gitee的OpenApi獲取自己的代碼倉庫列表,達(dá)到批量克隆項目的效果,文中通過代碼示例和圖文講解的非常詳細(xì),感興趣的小伙伴可以參考閱讀一下
    2024-04-04
  • 使用node.js搭建服務(wù)器

    使用node.js搭建服務(wù)器

    最近需要完成一個課程設(shè)計,被項目經(jīng)理(組長)分配寫界面功能,下面小編通過本文給大家分享使用使用node搭建小型服務(wù)器的方法,需要的朋友參考下
    2017-05-05

最新評論

定南县| 庄河市| 沾化县| 华容县| 甘德县| 通化市| 汤原县| 株洲县| 庆元县| 大丰市| 通州区| 九龙坡区| 侯马市| 封丘县| 冷水江市| 泾源县| 陇西县| 台北县| 洪江市| 鄄城县| 天气| 威远县| 泰顺县| 个旧市| 滁州市| 普格县| 福鼎市| 策勒县| 昆明市| 沁源县| 上饶市| 巴塘县| 黔西| 渝中区| 朝阳区| 凤阳县| 咸阳市| 锦州市| 汝州市| 青神县| 刚察县|