欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何優(yōu)雅地在Node應(yīng)用中進(jìn)行錯(cuò)誤異常處理

 更新時(shí)間:2019年11月25日 11:44:34   作者:scq000  
這篇文章主要介紹了如何優(yōu)雅地在Node應(yīng)用中進(jìn)行錯(cuò)誤處理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

不知道你有沒(méi)有遇到這樣一種情況,某天你寫(xiě)的代碼在線上突然發(fā)生錯(cuò)誤,然后你打開(kāi)控制臺(tái),卻對(duì)著打過(guò)包的錯(cuò)誤信息毫無(wú)頭緒?又或者說(shuō)是代碼在node端出現(xiàn)了問(wèn)題,你查看錯(cuò)誤日志的時(shí)候,卻發(fā)現(xiàn)日志文件中都是雜亂的錯(cuò)誤堆棧信息。

其實(shí)上面這些問(wèn)題都可以通過(guò)在代碼中引入合適的錯(cuò)誤機(jī)制進(jìn)行解決。大部分時(shí)候,由于程序員在開(kāi)發(fā)過(guò)程中更加關(guān)注需求的實(shí)現(xiàn),反而會(huì)忽視一些底層的工作。而錯(cuò)誤處理機(jī)制就相當(dāng)于我們代碼上的最后一道保險(xiǎn),在程序發(fā)生已知或者意外的問(wèn)題的時(shí)候,可以讓開(kāi)發(fā)者在第一時(shí)間獲取信息,從而快速定位并解決問(wèn)題。

常用的錯(cuò)誤處理機(jī)制

首先我們來(lái)了解一下目前前端領(lǐng)域到底有哪些錯(cuò)誤處理機(jī)制。

try catch

try...catch這種錯(cuò)誤處理機(jī)制一定是大家最熟悉的,Javascript語(yǔ)言內(nèi)置的錯(cuò)誤處理機(jī)制可以在檢測(cè)到代碼異常的時(shí)候直接進(jìn)行捕獲并處理。

function test() {
 try {
 throw new Error("error");
 } catch(err) {
 console.log("some error happened:");
 }
}

 
test()

node原生錯(cuò)誤處理機(jī)制

大多數(shù)Node.js核心API都提供的是利用回調(diào)函數(shù)處理錯(cuò)誤,例如:

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();

通過(guò)回調(diào)函數(shù)的err參數(shù)來(lái)檢查是否出現(xiàn)錯(cuò)誤,再進(jìn)行處理。之所以Node.js采用這種錯(cuò)誤處理機(jī)制,是因?yàn)楫惒椒椒ㄋa(chǎn)生的方法并不能簡(jiǎn)單地通過(guò)try...catch機(jī)制進(jìn)行攔截。

promise

Promise是用于處理異步調(diào)用的規(guī)范,而其提供的錯(cuò)誤處理機(jī)制,是通過(guò)catch方法進(jìn)行捕獲。

fs.mkdir("./temp").then(() => {
 fs.writeFile("./temp/foobar.txt", "hello");
}).catch(err => {
 console.log(err)
});

async/await + try catch

第三種錯(cuò)誤處理機(jī)制是采用async/await語(yǔ)法糖加上try...catch語(yǔ)句進(jìn)行的。這樣做的好處是異步和同步調(diào)用都能夠使用統(tǒng)一的方式進(jìn)行處理了。

async function one() {
 await two();
}

async function two() {
 await "hello";
 throw new Error("error");
}

async function test() {
 try {
 await one();
 } catch(error) {
 console.log(error);
 }
}

test();

解決方案

promisify

如果你的代碼中充斥著多種不同的錯(cuò)誤處理模式,那么維護(hù)起來(lái)是十分困難的。而且代碼的可讀性也會(huì)大大降低。因此,這里推薦采用的統(tǒng)一的解決方案。對(duì)于同步代碼來(lái)說(shuō),直接使用try...catch方式進(jìn)行捕獲處理即可,而對(duì)于異步代碼來(lái)說(shuō),建議轉(zhuǎn)換成Promise然后采用async/await + try...catch這種方式進(jìn)行處理。這樣風(fēng)格統(tǒng)一,程序的健壯性也大大加強(qiáng)。例如下面這個(gè)數(shù)據(jù)庫(kù)請(qǐng)求的代碼:

const database = require("database");

function promiseGet(query) {
 return new Promise((resolve, reject) => {
  database.get(query, (err, result) => {
   if (err) {
    reject(err);
   } else {
    resolve(result);
   }
  })
 })
}

async function main() {
 await promiseGet("foo");
}

main();

自定義錯(cuò)誤類型

直接使用系統(tǒng)原生的錯(cuò)誤信息通常會(huì)顯得太過(guò)單薄,不利于后續(xù)進(jìn)一步的分析和處理。所以為了讓代碼的錯(cuò)誤處理機(jī)制的功能更加強(qiáng)大,我們勢(shì)必要多花點(diǎn)精力進(jìn)行額外的改造。

可以通過(guò)擴(kuò)展基礎(chǔ)的Error類型來(lái)達(dá)到這一目的。

一般來(lái)說(shuō),要根據(jù)錯(cuò)誤發(fā)生的位置采用不同的錯(cuò)誤類型。

首先是應(yīng)用層錯(cuò)誤,它會(huì)保存額外的線索數(shù)據(jù):

class ApplicationError extends Error {
 constructor(message, options = {}) {
 assert(typeof message === 'string');
 assert(typeof options === 'object');
 assert(options !== null);
 super(message);

 // Attach relevant information to the error instance
 // (e.g., the username).
 for (const [key, value] of Object.entries(options)) {
  this[key] = value;
 }
 }

 get name() {
 return this.constructor.name;
 }
}

接著,可以再定義用戶接口的錯(cuò)誤類型,該類型主要用于直接返回給客戶端,比如錯(cuò)誤狀態(tài)碼等等。

class UserFacingError extends ApplicationError {
 constructor(message, options = {}) {
 super(message, options);
 }
}

class BadRequestError extends UserFacingError {
 get statusCode() {
 return 400
 }
}

class NotFoundError extends UserFacingError {
 get statusCode() {
 return 404
 }
}

另外,對(duì)于底層的數(shù)據(jù)庫(kù)錯(cuò)誤來(lái)說(shuō),可能需要更加細(xì)節(jié)的錯(cuò)誤信息。此時(shí)也可以根據(jù)業(yè)務(wù)需要進(jìn)行自定義:

class DatabaseError extends ApplicationError {
 get toString() {
 return "Errored happend in query: " + this.query + "\n" + this.message;
 }
}

// 使用的話
throw new DatabaseError("Other message", {
 query: query
});

化繁為簡(jiǎn),集中處理

express

有了基礎(chǔ)的錯(cuò)誤數(shù)據(jù)類型后,我們可以在代碼里針對(duì)不同的錯(cuò)誤類型采取不同的解決方案。 接下來(lái),以Express應(yīng)用為例講解一下使用方法。

app.use('/user', (req, res, next) => {
 const data = await database.getData(req.params.userId);
 if (!data) {
 throw new NotFoundError("User not found")
 }
 
 // do other thing
});

// 錯(cuò)誤處理中間件
app.use(async (err, req, res, next) => {
 if (err instanceof UserFacingError) {
 res.sendStatus(err.statusCode);
 // or
 res.status(err.statusCode).send(err.errorCode)
 } else {
 res.sendStatus(500)
 }
 
 // 記錄日志
 await logger.logError(err, 'parameter:', req.params, 'User Data:', req.user);
 // 發(fā)送郵件
 await sendMailToAdminIfCritical();
})

具體到實(shí)際場(chǎng)景中,需要在不同的路由中拋出不同的錯(cuò)誤類型,然后我們就可以通過(guò)在錯(cuò)誤處理中間件中進(jìn)行統(tǒng)一的處理。比如根據(jù)不同的錯(cuò)誤類型返回不同的錯(cuò)誤碼。還可以進(jìn)行記錄日志,發(fā)送郵件等操作。

database

數(shù)據(jù)庫(kù)發(fā)生錯(cuò)誤的時(shí)候,除了常規(guī)的拋出錯(cuò)誤,有時(shí)候你可能還需要進(jìn)行額外的重試或回退操作,如:

// 發(fā)生網(wǎng)絡(luò)錯(cuò)誤的時(shí)候隔200ms,重試3次
function query(queryStr, token, repeatTime = 0, delay = 200) {
 try {
 await db.query(queryStr);
 } catch (err) {
 if (err instanceof NetworkError && repeatTime < 3) {
  query(queryStr, token, repeatTime + 1, delay);
 }
 
 throw err;
 }
}

未處理錯(cuò)誤

對(duì)于未處理的錯(cuò)誤來(lái)說(shuō),我們可以使用node.js的unhandledRejection事件進(jìn)行監(jiān)聽(tīng):

process.on('unhandledRejection', error => {

 console.error('unhandledRejection', error);
 // To exit with a 'failure' code
 process.exit(1);
});

而且從Node.js 12.0開(kāi)始,可以使用以下命令啟動(dòng)程序:

node app.js --unhandled-rejections

這樣也能夠在發(fā)現(xiàn)未處理異常的時(shí)候進(jìn)行處理,官方支持了三種對(duì)應(yīng)的處理模式:

strict: Raise the unhandled rejection as an uncaught exception.

warn: Always trigger a warning, no matter if the unhandledRejection hook is set or not but do not print the deprecation warning.

none: Silence all warnings.

總結(jié)

最后,總結(jié)一下。為了實(shí)現(xiàn)可擴(kuò)展和可維護(hù)的錯(cuò)誤處理機(jī)制,我們可以需要注意以下幾個(gè)方面:

  • 使用自定義Error類,后續(xù)還能根據(jù)業(yè)務(wù)需要進(jìn)行擴(kuò)展
  • 將異步代碼轉(zhuǎn)換成Promise,然后統(tǒng)一使用async/await + try...catch的形式進(jìn)行錯(cuò)誤捕獲
  • 盡量采用統(tǒng)一的錯(cuò)誤處理中間件函數(shù)
  • 保持Error信息可理解,返回合適的錯(cuò)誤狀態(tài)和代碼
  • 對(duì)于未處理的錯(cuò)誤,要即使捕獲并記錄

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 使用Node.js實(shí)現(xiàn)一個(gè)文章生成器

    使用Node.js實(shí)現(xiàn)一個(gè)文章生成器

    本文將從零開(kāi)始,講解如何使用Node.js來(lái)實(shí)現(xiàn)一個(gè)文章生成器,node里面有很多優(yōu)秀的模塊,現(xiàn)在我們就借助node的fs模塊來(lái)操控文本,來(lái)實(shí)現(xiàn)我們想要的效果,感興趣的小伙伴跟著小編一起來(lái)看看吧
    2024-07-07
  • 詳解基于 Node.js 的輕量級(jí)云函數(shù)功能實(shí)現(xiàn)

    詳解基于 Node.js 的輕量級(jí)云函數(shù)功能實(shí)現(xiàn)

    這篇文章主要介紹了詳解基于 Node.js 的輕量級(jí)云函數(shù)功能實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • IDEA中配置node.js的實(shí)現(xiàn)步驟

    IDEA中配置node.js的實(shí)現(xiàn)步驟

    在IDEA中,如果要在安裝在遠(yuǎn)程主機(jī)或虛擬環(huán)境中的Node.js上運(yùn)行和調(diào)試應(yīng)用程序,則需要配置遠(yuǎn)程N(yùn)ode.js解釋器,本文主要介紹了IDEA中配置node.js的實(shí)現(xiàn)步驟,感興趣的可以了解一下
    2023-12-12
  • 如何使用Node.js爬取任意網(wǎng)頁(yè)資源并輸出PDF文件到本地

    如何使用Node.js爬取任意網(wǎng)頁(yè)資源并輸出PDF文件到本地

    這篇文章主要介紹了使用Node.js爬取任意網(wǎng)頁(yè)資源并輸出高質(zhì)量PDF文件到本地,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面小編就來(lái)和大家一起學(xué)習(xí)吧
    2019-06-06
  • nodejs對(duì)express中next函數(shù)的一些理解

    nodejs對(duì)express中next函數(shù)的一些理解

    這篇文章主要介紹了nodejs對(duì)express中next函數(shù)的一些理解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • node.js命令行教程圖文詳解

    node.js命令行教程圖文詳解

    本文先介紹原生的node.js實(shí)現(xiàn)命令行交互,了解原生的api,然后通過(guò)commander.js和inquirer.js實(shí)現(xiàn)一個(gè)完整的交互命令行工具。感興趣的朋友跟隨小編一起看看吧
    2019-05-05
  • Node.js 利用cheerio制作簡(jiǎn)單的網(wǎng)頁(yè)爬蟲(chóng)示例

    Node.js 利用cheerio制作簡(jiǎn)單的網(wǎng)頁(yè)爬蟲(chóng)示例

    本篇文章主要介紹了Node.js 利用cheerio制作簡(jiǎn)單的網(wǎng)頁(yè)爬蟲(chóng)示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • nodejs 中的讀取文件fs模塊示例詳解

    nodejs 中的讀取文件fs模塊示例詳解

    這篇文章主要為大家介紹了nodejs中的讀取文件fs模塊示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • node.js中的fs.stat方法使用說(shuō)明

    node.js中的fs.stat方法使用說(shuō)明

    這篇文章主要介紹了node.js中的fs.stat方法使用說(shuō)明,本文介紹了fs.stat的方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • node如何實(shí)現(xiàn)簡(jiǎn)單的腳手架淺析

    node如何實(shí)現(xiàn)簡(jiǎn)單的腳手架淺析

    在工作中,需要開(kāi)發(fā)一個(gè)腳手架,用于給相關(guān)用戶提供相關(guān)的開(kāi)發(fā)便利性,下面這篇文章主要給大家介紹了關(guān)于node如何實(shí)現(xiàn)簡(jiǎn)單的腳手架的相關(guān)資料,需要的朋友可以參考下
    2022-05-05

最新評(píng)論