Vue中如何優雅的捕獲 Promise 異常詳解
常規的異常捕獲方式
在 Promise 提供瞭一個 .catch
方法用來捕獲異常,假設有很多異步請求,通常會把 .catch
方法放在鏈式調用的最末尾。正常情況下末尾的 .catch
不會被觸發,但當前面的任何一個 Promise rejected 之後,.catch
就可以捕獲到異常
promiseFunction1({ year: unref(year), }) .then((res) => { if (res.status === 200) { return promiseFunction2(res.data?.name || ""); } }) .then((res) => { if (res.status === 200) { const getUserInfo = userInfoResult.data; // ... 具體操作 } }) // 異常捕獲 .catch((error) => console.error(error));
如果使用 Promise 的語法糖 async / await 的話,可以使用更符合直覺的 try...catch
捕獲異常,上面這個請求例子就可以修改為
async function handleUserInfo() { try { const userResult = await promiseFunction1({ year: unref(year) }); if (userResult.status !== 200) return; const userInfoResult = await promiseFunction2(res.data?.name || ""); if (userInfoResult.status !== 200) return; getUserInfo = userInfoResult.data; // ... 具體操作 } catch (error) { console.error(error); } }
不管是 .then
方法還是 try...catch
都需要增加一些代碼操作,最重要的是可能會忘記捕獲異常,所以下面介紹兩個更好一些的解決方案
好一些的方式:await-to-js
await-to-js 是一個大佬對 async / await 返回內容進行的一層封裝,在不用 try...catch
的方式下也能進行異常捕獲
在使用前需要先引入這個依賴:npm i await-to-js
,下面我們來改寫簡化一下之前的異常捕獲方式
import to from 'await-to-js'; async function handleUserInfo() { const [userError, userResult] = await promiseFunction1({ year: unref(year) }) if (userResult.status !== 200) return const [userInfoError, userInfoResult] = await promiseFunction2(res.data?.name || "") if (userInfoResult.status !== 200) return getUserInfo = userInfoResult.data // ... 具體操作 }
await-to-js 的實現也就短短幾行代碼,本質就是對 Promise 的 .then
和 .catch
返回結果進行組合,然後整體作為一個 Promise 再返回出去
export function to<T, U = Error> ( promise: Promise<T>, errorExt?: object // 傳遞給 err 對象的附加信息 ): 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;
雖然 await-to-js 簡化瞭代碼,但還是需要引入依賴,對請求進行一層包裹,還是稍微麻煩瞭一點,如果我們對異常處理沒有特殊處理的需要,僅僅隻是捕獲並且拋出,為瞭追求更簡潔的代碼;
或者項目中有非常多的地方沒有異常捕獲,需要一個一個的手工增加非常麻煩,針對這兩種情況,還有沒有更好的辦法呢?
更好的方式:全局捕獲
在 Vue2 的全局配置中提供瞭一個 errorHandler
鉤子可以用於捕獲全局異常,但是最低版本要求 2.2.0+
errorHandler
第一個參數 err
是具體的錯誤信息,第二個參數 vm
是 Vue 組件信息,第三個參數 info
是 Vue 特定的錯誤信息,比如錯誤所在的生命周期鉤子。一般為瞭捕獲 Vue 特定的 info
信息,在內部處理時還會加上一層 nextTick
,確保捕獲的是 DOM 渲染完成之後的信息。另外最好在根據不同環境配置判斷是否需要捕獲異常,增加程序的靈活性
// errorHandler 使用示例 import Vue from 'vue' // 配置項形式:'development' | ['development', 'production'] const { errorLog: needErrorLog } = settings // 根據配置判斷什麼環境下需要捕獲異常 function checkNeedErrorLog() { const env = process.env.NODE_ENV if (isString(needErrorLog)) { return env === needErrorLog } if (isArray(needErrorLog)) { return needErrorLog.includes(env) } return false } // 全局異常捕獲 if (checkNeedErrorLog()) { Vue.config.errorHandler = function (err, vm, info) { Vue.nextTick(() => { console.error(`[${projectName}]: ${err}。`, `Vue info: ${info}`, vm) }) } }
根據官網的描述,不同的 Vue 版本捕獲的信息不同,所以建議最好是更新 Vue 2.6.0 以上的版本,這樣就可以全局捕獲到 Promise 和 async / await 拋出的異常瞭,
從 2.2.0 起,errorHandler
鉤子也會捕獲組件生命周期鉤子裡的錯誤。同樣的,當這個鉤子是 undefined
時,被捕獲的錯誤會通過 console.error
輸出而避免應用崩潰
從 2.4.0 起,errorHandler
鉤子也會捕獲 Vue 自定義事件處理函數內部的錯誤
從 2.6.0 起,errorHandler
鉤子也會捕獲 v-on
DOM 監聽器內部拋出的錯誤。另外,如果任何被覆蓋的鉤子或處理函數返回一個 Promise 鏈 (例如 async 函數),則來自其 Promise 鏈的錯誤也會被處理
在 Vue3 中,除瞭提供 errorHandler
鉤子外,還提供瞭 warnHandler
鉤子,兩個鉤子的用法相同,區別是是 warnHandler
隻在開發環境生效,生產環境會被忽略
app.config.warnHandler = function(msg, vm, trace) { // `trace` 是組件的繼承關系追蹤 }
以上就是Vue中如何優雅的捕獲 Promise 異常詳解的詳細內容,更多關於Vue Promise 異常捕獲的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- vue中Promise的使用方法詳情
- 前端常見面試題之async/await和promise的區別
- JS異步代碼單元測試之神奇的Promise
- JavaScript詳解使用Promise處理回調地獄與async await修飾符
- 使用async await處理錯誤方法示例