Vue中的errorHandler異常捕獲問(wèn)題
Vue errorHandler異常捕獲
異常捕獲介紹
1.在日常前端開(kāi)發(fā)中對(duì)于異常監(jiān)控的方式可以采用 window.onerror 方式進(jìn)行監(jiān)聽(tīng)
window.onerror = function(message, source, lineno, colno, error) { // message:錯(cuò)誤信息(字符串) // source:發(fā)生錯(cuò)誤的腳本URL // lineno:發(fā)生錯(cuò)誤的行號(hào) // colno:發(fā)生錯(cuò)誤的列號(hào) // error:Error對(duì)象 } //或者 window.addEventListener('error', function(e) { console.log(e) console.log(e.target) })
2.在vue中需要使用errorHandler方法
onerror方法無(wú)法捕獲Vue組件信息
Vue.config.errorHandler = function (err, vm, info) { // err: 具體錯(cuò)誤信息 // vm: 當(dāng)前錯(cuò)誤所在的Vue實(shí)例 // info: 錯(cuò)誤所在的生命周期鉤子 }
errorHandler實(shí)際應(yīng)用
針對(duì)項(xiàng)目中錯(cuò)誤的js語(yǔ)法和接口請(qǐng)求報(bào)錯(cuò)進(jìn)行捕獲,需要注意的是接口捕獲需要手動(dòng)捕獲
1.在main.js中注冊(cè)
//因?yàn)榻涌趫?bào)錯(cuò)需要手動(dòng)捕獲 創(chuàng)建公用方法 const errorHandler = (err, vm, info) => { if(err.isAxiosError){ //axios請(qǐng)求錯(cuò)誤 }else{ //js語(yǔ)法錯(cuò)誤 console.log('err:'err.toString()) } } //調(diào)用 Vue.config.errorHandler = errorHandler //axios手動(dòng)捕獲使用 綁定 prototype Vue.prototype.$throw = (error) => errorHandler(error, this)
2.axios錯(cuò)誤捕獲
在封裝好的axios請(qǐng)求中進(jìn)行錯(cuò)誤響應(yīng)捕獲,將錯(cuò)誤信息交給 errorHadaler 函數(shù)進(jìn)行處理
Vue.$throw(error) //或 Vue.prototype.$throw(error)
對(duì)于error信息的解析
1.通過(guò)Json.stringify()對(duì)err進(jìn)行序列化
const errorHandler = (err, vm, info) => { if(err.isAxiosError){ //axios請(qǐng)求錯(cuò)誤為手動(dòng)捕獲 不需要進(jìn)行解析處理 }else{ const errJson = JSON.stringify(err, Object.getOwnPropertyNames(err), 2) console.log(JSON.parse(errJson )) } }
2.通過(guò)error-stack-parser解析error堆棧
安裝方式:
npm install error-stack-parser yarn add error-stack-parser
//引入error-stack-parser import ErrorStackParser from 'error-stack-parser' const errorHandler = (err, vm, info) => { if(err.isAxiosError){ //axios請(qǐng)求錯(cuò)誤為手動(dòng)捕獲 不需要進(jìn)行解析處理 }else{ const errJson = ErrorStackParser.parse(err)[0] console.log(errJson) //通過(guò)fileName截取頁(yè)面名稱(chēng) const fileName = stackInfo.fileName.match(/src.*?.vue/g)[0] console.log(fileName) } }
vue.config.errorHandler 錯(cuò)誤處理調(diào)研
在 vue2.6.x 及之后版本中(僅限于此API未被毀滅性更新前)使用全局 errorHandler 鉤子來(lái)進(jìn)行 vue 組件中所拋錯(cuò)誤的捕捉與處理。
現(xiàn)狀
vue2.6 之前,errorHandler 只能捕捉同步函數(shù)拋出的錯(cuò)誤,而在實(shí)際開(kāi)發(fā)中我們關(guān)心得更多的是調(diào)用接口時(shí)可能拋出的錯(cuò)誤,ES7之后通常使用 async await 的方式進(jìn)行接口調(diào)用,對(duì)于async函數(shù)中拋出的錯(cuò)誤errorHandler并不能捕捉到。
因此我們使用了裝飾器(Decorator)進(jìn)行錯(cuò)誤捕捉,方法可行,癢點(diǎn)在于需要在很多個(gè)組件中引入裝飾器,然后放置在每一個(gè)需要的位置(還有個(gè)近乎絕癥的“痛點(diǎn)”是 vetur 插件對(duì)“不規(guī)范使用decorator”的紅色警告)。
當(dāng)前使用示例(盡可能簡(jiǎn)化版)
// errorConfigs.js import { debounce } from 'lodash'; const DEBOUNCE_TIME = 500; const errorProcessorConfigs = [{ assert (error) { return ErrorAssert.isUserInfoNotExist(error); // ErrorAssert為內(nèi)部Error斷言庫(kù),使用了webpack的ProvidePlugin聲明 }, processor: debounce(() => alert('用戶信息不存在'), DEBOUNCE_TIME) }, { assert (error) { return ErrorAssert.isAppInfoNotExist(error); }, processor: debounce(() => alert('應(yīng)用信息不存在'), DEBOUNCE_TIME) }] // errorProcessor.js import errorProcessorConfigs from '@src/configs/errorConfigs'; function errorProcessor(error) { let errorProcessorConfig = errorProcessorConfigs.find(config => config.assert(error)); if (errorProcessorConfig !== undefined) { errorProcessorConfig.processor(error); } throw error; // 處理完之后繼續(xù)將錯(cuò)誤拋出以中斷程序流程 }; export default errorProcessor; // errorCatcher.js import errorProcessor from './errorProcessor'; function errorCatcher(target, name, descriptor) { const originFunc = descriptor.value; descriptor.value = async function () { try { return await originFunc.apply(this, arguments); } catch (error) { return errorProcessor(error); } }; return descriptor; }; export default errorCatcher; // xxx.vue /* template */ <script> import errorCatcher from '@services/errorCatcher'; import checkLogin from '@services/checkLogin'; import resources from '@services/resources'; export default { @errorCatcher async created () { await checkLogin(); this.fetchUserInfo(); }, methods: { @errorCatcher async fetchUserInfo () { const userInfo = await resources.user.fetch(); // ... }, } }; </script> /* style */
console:
應(yīng)用
// main.js import Vue from 'vue'; import errorProcessor from '@services/errorProcessor'; Vue.config.errorHandler = errorProcessor; /* ... */ // xxx.vue /* template */ <script> import checkLogin from '@services/checkLogin'; import resources from '@services/resources'; export default { async created () { await checkLogin(); this.fetchUserInfo(); }, methods: { async fetchUserInfo () { const userInfo = await resources.user.fetch(); // ... }, } }; </script> /* style */
對(duì)比
裝飾器 | errorHandler | |
---|---|---|
優(yōu)勢(shì) | 1.使用靈活,可多個(gè)裝飾器組裝使用;2.裝飾器可以接收參數(shù),進(jìn)行更高階的應(yīng)用; | 1.全局設(shè)置,一處設(shè)置處處受益,使用較為簡(jiǎn)潔;2. 可以直接拿到 this,獲取更多信息,進(jìn)行更多操作;3. info 可輔助定位錯(cuò)誤源; |
劣勢(shì) | 1.在每一個(gè)需要的函數(shù)處都需要使用裝飾器進(jìn)行包裝,組件中也需要引入裝飾器模塊;2.裝飾器被babel編譯后細(xì)微的增加文件體積;3.編譯期生效,因此如果 errorProcessorConfigs想引入 router 就需要進(jìn)行一些特殊處理(如將routes 配置放在 main.js 中添加,或者通過(guò)變量方式傳入) | 1.無(wú)法向錯(cuò)誤處理中傳入?yún)?shù);2.全局只能有一個(gè),如果想針對(duì)不同場(chǎng)景下拋出的同一類(lèi) error 進(jìn)行不同處理,則需要加入判斷邏輯,影響函數(shù)純粹性。3.捕捉錯(cuò)誤條件限制于同步函數(shù)或函數(shù)返回promise鏈。4.watch中調(diào)用的異步函數(shù)暫時(shí)無(wú)法被捕捉 |
心得
裝飾器錯(cuò)誤處理方式略顯繁重,但并不會(huì)被errorHandler完全取締,如果想讓errorHandler盡可能的捕捉到出現(xiàn)的錯(cuò)誤,則可能需要對(duì)代碼進(jìn)行一些更為嚴(yán)格的調(diào)整(構(gòu)建promise鏈),可以根據(jù)實(shí)際的場(chǎng)景,將二者結(jié)合使用,以產(chǎn)生更大的受益(舉個(gè)例子:某些場(chǎng)景下的錯(cuò)誤可以使用裝飾器處理并吞掉,不走全局處理)。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用Vue父子組件通信實(shí)現(xiàn)todolist的功能示例代碼
這篇文章主要給大家介紹了關(guān)于如何使用Vue父子組件通信實(shí)現(xiàn)todolist的功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Ant?Design?Vue?修改表格頭部樣式的詳細(xì)代碼
這篇文章主要介紹了Ant?Design?Vue?修改表格頭部樣式,首先用到的是customHeaderRow這個(gè)API,類(lèi)型是一個(gè)函數(shù),本文通過(guò)完整代碼給大家詳細(xì)講解,需要的朋友可以參考下2022-10-10el-tab設(shè)置默認(rèn)激活的標(biāo)簽頁(yè)實(shí)現(xiàn)步驟
這篇文章主要給大家介紹了關(guān)于el-tab設(shè)置默認(rèn)激活的標(biāo)簽頁(yè)實(shí)現(xiàn)步驟,文中通過(guò)代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09vue3-vue-router創(chuàng)建靜態(tài)路由和動(dòng)態(tài)路由方式
這篇文章主要介紹了vue3-vue-router創(chuàng)建靜態(tài)路由和動(dòng)態(tài)路由方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10elementUI的table表格改變數(shù)據(jù)不更新問(wèn)題解決
最近在做vue的項(xiàng)目時(shí)發(fā)現(xiàn)了一個(gè)問(wèn)題,今天就來(lái)解決一下,本文主要介紹了elementUI的table表格改變數(shù)據(jù)不更新問(wèn)題解決,感興趣的可以了解一下2022-02-02Vue中關(guān)于computed計(jì)算屬性的妙用
這篇文章主要介紹了Vue中關(guān)于computed計(jì)算屬性的妙用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11詳解為什么Vue中不要用index作為key(diff算法)
這篇文章主要介紹了詳解為什么Vue中不要用index作為key(diff算法),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04