Vue中的errorHandler异常捕获问题

 更新时间:2023年05月20日 14:39:26   作者:初升晨光  
这篇文章主要介绍了Vue中的errorHandler异常捕获问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Vue errorHandler异常捕获

异常捕获介绍

1.在日常前端开发中对于异常监控的方式可以采用 window.onerror 方式进行监听

window.onerror = function(message, source, lineno, colno, error) {
	 	// message:错误信息(字符串)
		// source:发生错误的脚本URL
		// lineno:发生错误的行号
		// colno:发生错误的列号
		// error:Error对象
	}
	//或者
	window.addEventListener('error', function(e) { 
	  console.log(e)
	  console.log(e.target)
	})

2.在vue中需要使用errorHandler方法

onerror方法无法捕获Vue组件信息

Vue.config.errorHandler = function (err, vm, info) {
	  // err: 具体错误信息
	  // vm: 当前错误所在的Vue实例
	  // info: 错误所在的生命周期钩子
	}

errorHandler实际应用

针对项目中错误的js语法和接口请求报错进行捕获,需要注意的是接口捕获需要手动捕获 

1.在main.js中注册

//因为接口报错需要手动捕获 创建公用方法
const errorHandler = (err, vm, info) => {
	if(err.isAxiosError){
		//axios请求错误
	}else{
		//js语法错误
		console.log('err:'err.toString())
	}
}
//调用
Vue.config.errorHandler = errorHandler
//axios手动捕获使用 绑定 prototype
Vue.prototype.$throw = (error) => errorHandler(error, this)

2.axios错误捕获

在封装好的axios请求中进行错误响应捕获,将错误信息交给 errorHadaler 函数进行处理

Vue.$throw(error)
//或 
Vue.prototype.$throw(error)

对于error信息的解析

1.通过Json.stringify()对err进行序列化

const errorHandler = (err, vm, info) => {
	if(err.isAxiosError){
		//axios请求错误为手动捕获 不需要进行解析处理 
	}else{
		const errJson = JSON.stringify(err, Object.getOwnPropertyNames(err), 2)
		console.log(JSON.parse(errJson ))
	}
}

2.通过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请求错误为手动捕获 不需要进行解析处理 
	}else{
		const errJson = ErrorStackParser.parse(err)[0]
		console.log(errJson)
		//通过fileName截取页面名称
		const fileName = stackInfo.fileName.match(/src.*?.vue/g)[0]
		console.log(fileName)
	}
}

vue.config.errorHandler 错误处理调研

在 vue2.6.x 及之后版本中(仅限于此API未被毁灭性更新前)使用全局 errorHandler 钩子来进行 vue 组件中所抛错误的捕捉与处理。

现状

vue2.6 之前,errorHandler 只能捕捉同步函数抛出的错误,而在实际开发中我们关心得更多的是调用接口时可能抛出的错误,ES7之后通常使用 async await 的方式进行接口调用,对于async函数中抛出的错误errorHandler并不能捕捉到。

因此我们使用了装饰器(Decorator)进行错误捕捉,方法可行,痒点在于需要在很多个组件中引入装饰器,然后放置在每一个需要的位置(还有个近乎绝症的“痛点”是 vetur 插件对“不规范使用decorator”的红色警告)。

当前使用示例(尽可能简化版)

// errorConfigs.js
import { debounce } from 'lodash';
const DEBOUNCE_TIME = 500;
const errorProcessorConfigs = [{
  assert (error) {
    return ErrorAssert.isUserInfoNotExist(error); // ErrorAssert为内部Error断言库,使用了webpack的ProvidePlugin声明
  },
  processor: debounce(() => alert('用户信息不存在'), DEBOUNCE_TIME)
}, {
  assert (error) {
    return ErrorAssert.isAppInfoNotExist(error);
  },
  processor: debounce(() => alert('应用信息不存在'), 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; // 处理完之后继续将错误抛出以中断程序流程
};
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:

应用

// 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 */

对比

装饰器errorHandler
优势1.使用灵活,可多个装饰器组装使用;2.装饰器可以接收参数,进行更高阶的应用;1.全局设置,一处设置处处受益,使用较为简洁;2. 可以直接拿到 this,获取更多信息,进行更多操作;3. info 可辅助定位错误源;
劣势1.在每一个需要的函数处都需要使用装饰器进行包装,组件中也需要引入装饰器模块;2.装饰器被babel编译后细微的增加文件体积;3.编译期生效,因此如果 errorProcessorConfigs想引入 router 就需要进行一些特殊处理(如将routes 配置放在 main.js 中添加,或者通过变量方式传入)1.无法向错误处理中传入参数;2.全局只能有一个,如果想针对不同场景下抛出的同一类 error 进行不同处理,则需要加入判断逻辑,影响函数纯粹性。3.捕捉错误条件限制于同步函数或函数返回promise链。4.watch中调用的异步函数暂时无法被捕捉

心得

装饰器错误处理方式略显繁重,但并不会被errorHandler完全取缔,如果想让errorHandler尽可能的捕捉到出现的错误,则可能需要对代码进行一些更为严格的调整(构建promise链),可以根据实际的场景,将二者结合使用,以产生更大的受益(举个例子:某些场景下的错误可以使用装饰器处理并吞掉,不走全局处理)。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 使用Vue父子组件通信实现todolist的功能示例代码

    使用Vue父子组件通信实现todolist的功能示例代码

    这篇文章主要给大家介绍了关于如何使用Vue父子组件通信实现todolist的功能的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Vue具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-04-04
  • Ant Design Vue 修改表格头部样式的详细代码

    Ant Design Vue 修改表格头部样式的详细代码

    这篇文章主要介绍了Ant Design Vue 修改表格头部样式,首先用到的是customHeaderRow这个API,类型是一个函数,本文通过完整代码给大家详细讲解,需要的朋友可以参考下
    2022-10-10
  • el-tab设置默认激活的标签页实现步骤

    el-tab设置默认激活的标签页实现步骤

    这篇文章主要给大家介绍了关于el-tab设置默认激活的标签页实现步骤,文中通过代码介绍的非常详细,对大家的学习或者工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-09-09
  • vue3-vue-router创建静态路由和动态路由方式

    vue3-vue-router创建静态路由和动态路由方式

    这篇文章主要介绍了vue3-vue-router创建静态路由和动态路由方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10
  • elementUI的table表格改变数据不更新问题解决

    elementUI的table表格改变数据不更新问题解决

    最近在做vue的项目时发现了一个问题,今天就来解决一下,本文主要介绍了elementUI的table表格改变数据不更新问题解决,感兴趣的可以了解一下
    2022-02-02
  • Vue中关于computed计算属性的妙用

    Vue中关于computed计算属性的妙用

    这篇文章主要介绍了Vue中关于computed计算属性的妙用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • 详解为什么Vue中不要用index作为key(diff算法)

    详解为什么Vue中不要用index作为key(diff算法)

    这篇文章主要介绍了详解为什么Vue中不要用index作为key(diff算法),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • Vue Router添加全局$router属性的示例详解

    Vue Router添加全局$router属性的示例详解

    这篇文章主要介绍了Vue-Router-添加全局$router属性,在 Vue 中有一个 mixin 方法,这个方法会在每个组件创建之前被调用,我们可以在这个方法中将 VueRouter 实例挂载到 Vue 实例上,本文给大家介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • vue3中proxy的基本用法说明

    vue3中proxy的基本用法说明

    这篇文章主要介绍了vue3中proxy的基本用法说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • vue3中Hook使用以及Hook结合自定义指令

    vue3中Hook使用以及Hook结合自定义指令

    这篇文章主要介绍了vue3中Hook使用以及Hook结合自定义指令方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08

最新评论