淺析async await錯誤處理問題及如何不使用try catch優雅地進行錯誤處理


一、Async 函數的錯誤處理

  async 函數的語法不難,難在錯誤處理上。先來看下面的例子:

  我們可以看到 Promise 報錯后,a = await 1 並沒有被執行。即當 async 函數中只要一個 await 出現 reject 狀態,則后面的 await 都不會被執行。

  解決辦法是:可以添加 try catch。

// 正確的寫法
let a; async function correct() { try { await Promise.reject('error') } catch (error) { console.log(error); } a = await 1; return a; } correct().then(v => console.log(a));

  這樣就會先打印 error,再打印 1。因此,如果有多個 await 則可以將其都放在 try/catch 中,但很顯然,這樣並不優雅。

// 我們需要對每一次異步操作進行錯誤處理
function async asyncTask(cb) { try { const asyncFuncARes = await asyncFuncA() } catch(error) { return new Error(error) } try { const asyncFuncBRes = await asyncFuncB(asyncFuncARes) } catch(error) { return new Error(error) } try { const asyncFuncCRes = await asyncFuncC(asyncFuncBRes) } catch(error) { return new Error(error) } }

二、npm包:await-to-js 及源碼分析

  作者是這樣介紹這個庫的:Async await wrapper for easy error handling without try-catch。中文翻譯過來就是:無需 try-catch 即可輕松處理錯誤的異步等待包裝器。

  與上面對比,使用了await-to-js之后,我們可以這樣的處理錯誤:

import to from './to.js'; function async asyncTask() { const [err, asyncFuncARes]  = await to(asyncFuncA()) if(err) throw new (error); const [err, asyncFuncBRes]  = await to(asyncFuncB(asyncFuncARes)) if(err) throw new (error); const [err, asyncFuncCRes]  = await to(asyncFuncC(asyncFuncBRes) if(err) throw new (error); }

  簡潔多了,看看源碼,沒寫想到只有 15 行,完全都可以自己作為一個公共方法使用即可。

export function to<T, U = Error> ( promise: Promise<T>, errorExt?: object ): Promise<[U, undefined] | [null, T]> { return promise .then<[null, T]>((data: T) => [null, data]) .catch<[U, undefined]>((err: U) => { if (errorExt) { const parsedError = Object.assign({}, err, errorExt); return [parsedError, undefined]; } return [err, undefined]; }); } export default to;

  上面是TS版的源碼,但是考慮到有些同學可能還沒接觸過TS,我着重分析一下下面這版JS版的源碼。

export function to(promise, errorExt) { return promise .then((data) => [null, data]) .catch((err) => {   if (errorExt) {   const parsedError = Object.assign({}, err, errorExt);   return [parsedError, undefined];   }    return [err, undefined];   }); } export default to;

  這里我們先拋開 errorExt 這個自定義的錯誤文本,可以看出:其代碼的邏輯用中文解釋是這樣的:

  • 無論成功還是失敗,都返回一個數組,數組的第一項是和錯誤相關的,數組的第二項是和響結果相關的
  • 成功的話,數組第一項也就是錯誤信息為空,數組第二項也就是響應結果正常返回
  • 失敗的話,數組第一項也就是錯誤信息為錯誤信息,數組第二項也就是響應結果返回undefined

  經過上面的分析發現:其實挺簡單的,但是,又確實挺巧妙的,我們也並不是做不到,而不是想不到。

  這里我們再來看函數 to 的第二個參數 errorExt,不難發現這其實就是拿來用戶自定義錯誤信息的,通過 Object.assign 將正常返回的 error 和用戶自定義的,合並到一個對象里面供用戶自己選擇。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM