这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

一、错误类型

任何一个框架,对于错误的处理都是一种必备的能力

Vue 中,则是定义了一套对应的错误处理规则给到使用者,且在源代码级别,对部分必要的过程做了一定的错误处理。

主要的错误来源包括:

  • 后端接口错误
  • 代码中本身逻辑错误

二、如何处理

后端接口错误

通过axiosinterceptor实现网络请求的response先进行一层拦截

apiClient.interceptors.response.use(
response => {
return response;
},
error => {
if (error.response.status == 401) {
router.push({ name: "Login" });
} else {
message.error("出错了");
return Promise.reject(error);
}
}
);

代码逻辑问题

全局设置错误处理

设置全局错误处理函数

Vue.config.errorHandler = function (err, vm, info) {
// handle error
// `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
// 只在 2.2.0+ 可用
}

errorHandler指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例

不过值得注意的是,在不同Vue 版本中,该全局 API 作用的范围会有所不同:

从 2.2.0 起,这个钩子也会捕获组件生命周期钩子里的错误。同样的,当这个钩子是 undefined 时,被捕获的错误会通过 console.error 输出而避免应用崩

从 2.4.0 起,这个钩子也会捕获 Vue 自定义事件处理函数内部的错误了

从 2.6.0 起,这个钩子也会捕获 v-on DOM 监听器内部抛出的错误。另外,如果任何被覆盖的钩子或处理函数返回一个 Promise 链 (例如 async 函数),则来自其 Promise 链的错误也会被处理

生命周期钩子

errorCaptured是 2.5.0 新增的一个生命钩子函数,当捕获到一个来自子孙组件的错误时被调用

基本类型

(err: Error, vm: Component, info: string) => ?boolean

此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播

参考官网,错误传播规则如下:

  • 默认情况下,如果全局的 config.errorHandler 被定义,所有的错误仍会发送它,因此这些错误仍然会向单一的分析服务的地方进行汇报
  • 如果一个组件的继承或父级从属链路中存在多个 errorCaptured 钩子,则它们将会被相同的错误逐个唤起。
  • 如果此 errorCaptured 钩子自身抛出了一个错误,则这个新错误和原本被捕获的错误都会发送给全局的 config.errorHandler
  • 一个 errorCaptured 钩子能够返回 false 以阻止错误继续向上传播。本质上是说“这个错误已经被搞定了且应该被忽略”。它会阻止其它任何会被这个错误唤起的 errorCaptured 钩子和全局的 config.errorHandler

下面来看个例子

定义一个父组件cat

Vue.component('cat', {
template:`
<div>
<h1>Cat: </h1>
<slot></slot>
</div>`,
props:{
name:{
required:true,
type:String
}
},
errorCaptured(err,vm,info) {
console.log(`cat EC: ${err.toString()}\ninfo: ${info}`);
return false;
} });

定义一个子组件kitten,其中dontexist()并没有定义,存在错误

Vue.component('kitten', {
template:'<div><h1>Kitten: {{ dontexist() }}</h1></div>',
props:{
name:{
required:true,
type:String
}
}
});

页面中使用组件

<div id="app" v-cloak>
<cat name="my cat">
<kitten></kitten>
</cat>
</div>

在父组件的errorCaptured则能够捕获到信息

cat EC: TypeError: dontexist is not a function
info: render

三、源码分析

异常处理源码

源码位置:/src/core/util/error.js

// Vue 全局配置,也就是上面的Vue.config
import config from '../config'
import { warn } from './debug'
// 判断环境
import { inBrowser, inWeex } from './env'
// 判断是否是Promise,通过val.then === 'function' && val.catch === 'function', val !=== null && val !== undefined
import { isPromise } from 'shared/util'
// 当错误函数处理错误时,停用deps跟踪以避免可能出现的infinite rendering
// 解决以下出现的问题https://github.com/vuejs/vuex/issues/1505的问题
import { pushTarget, popTarget } from '../observer/dep' export function handleError (err: Error, vm: any, info: string) {
// Deactivate deps tracking while processing error handler to avoid possible infinite rendering.
pushTarget()
try {
// vm指当前报错的组件实例
if (vm) {
let cur = vm
// 首先获取到报错的组件,之后递归查找当前组件的父组件,依次调用errorCaptured 方法。
// 在遍历调用完所有 errorCaptured 方法、或 errorCaptured 方法有报错时,调用 globalHandleError 方法
while ((cur = cur.$parent)) {
const hooks = cur.$options.errorCaptured
// 判断是否存在errorCaptured钩子函数
if (hooks) {
// 选项合并的策略,钩子函数会被保存在一个数组中
for (let i = 0; i < hooks.length; i++) {
// 如果errorCaptured 钩子执行自身抛出了错误,
// 则用try{}catch{}捕获错误,将这个新错误和原本被捕获的错误都会发送给全局的config.errorHandler
// 调用globalHandleError方法
try {
// 当前errorCaptured执行,根据返回是否是false值
// 是false,capture = true,阻止其它任何会被这个错误唤起的 errorCaptured 钩子和全局的 config.errorHandler
// 是true capture = fale,组件的继承或父级从属链路中存在的多个 errorCaptured 钩子,会被相同的错误逐个唤起
// 调用对应的钩子函数,处理错误
const capture = hooks[i].call(cur, err, vm, info) === false
if (capture) return
} catch (e) {
globalHandleError(e, cur, 'errorCaptured hook')
}
}
}
}
}
// 除非禁止错误向上传播,否则都会调用全局的错误处理函数
globalHandleError(err, vm, info)
} finally {
popTarget()
}
}
// 异步错误处理函数
export function invokeWithErrorHandling (
handler: Function,
context: any,
args: null | any[],
vm: any,
info: string
) {
let res
try {
// 根据参数选择不同的handle执行方式
res = args ? handler.apply(context, args) : handler.call(context)
// handle返回结果存在
// res._isVue an flag to avoid this being observed,如果传入值的_isVue为ture时(即传入的值是Vue实例本身)不会新建observer实例
// isPromise(res) 判断val.then === 'function' && val.catch === 'function', val !=== null && val !== undefined
// !res._handled _handle是Promise 实例的内部变量之一,默认是false,代表onFulfilled,onRejected是否被处理
if (res && !res._isVue && isPromise(res) && !res._handled) {
res.catch(e => handleError(e, vm, info + ` (Promise/async)`))
// avoid catch triggering multiple times when nested calls
// 避免嵌套调用时catch多次的触发
res._handled = true
}
} catch (e) {
// 处理执行错误
handleError(e, vm, info)
}
return res
} //全局错误处理
function globalHandleError (err, vm, info) {
// 获取全局配置,判断是否设置处理函数,默认undefined
// 已配置
if (config.errorHandler) {
// try{}catch{} 住全局错误处理函数
try {
// 执行设置的全局错误处理函数,handle error 想干啥就干啥
return config.errorHandler.call(null, err, vm, info)
} catch (e) {
// 如果开发者在errorHandler函数中手动抛出同样错误信息throw err
// 判断err信息是否相等,避免log两次
// 如果抛出新的错误信息throw err Error('你好毒'),将会一起log输出
if (e !== err) {
logError(e, null, 'config.errorHandler')
}
}
}
// 未配置常规log输出
logError(err, vm, info)
} // 错误输出函数
function logError (err, vm, info) {
if (process.env.NODE_ENV !== 'production') {
warn(`Error in ${info}: "${err.toString()}"`, vm)
}
/* istanbul ignore else */
if ((inBrowser || inWeex) && typeof console !== 'undefined') {
console.error(err)
} else {
throw err
}
}

小结

  • handleError在需要捕获异常的地方调用,首先获取到报错的组件,之后递归查找当前组件的父组件,依次调用errorCaptured 方法,在遍历调用完所有 errorCaptured 方法或 errorCaptured 方法有报错时,调用 globalHandleError 方法
  • globalHandleError调用全局的 errorHandler 方法,再通过logError判断环境输出错误信息
  • invokeWithErrorHandling更好的处理异步错误信息
  • logError判断环境,选择不同的抛错方式。非生产环境下,调用warn方法处理错误

参考文献

  • https://juejin.cn/post/6844904096936230925

  • https://segmentfault.com/a/1190000018606181

你是怎么处理vue项目中的错误的?的更多相关文章

  1. vue 项目中实用的小技巧

    # 在Vue 项目中引入Bootstrap 有时在vue项目中会根据需求引入Bootstrap,而Bootstrap又是依赖于jQuery的,在使用npm按照时,可能会出现一系列的错误 1.安装jQu ...

  2. 如何在VUE项目中添加ESLint

    如何在VUE项目中添加ESLint 1. 首先在项目的根目录下 新建 .eslintrc.js文件,其配置规则可以如下:(自己小整理了一份),所有的代码如下: // https://eslint.or ...

  3. 在vue项目中, mock数据

    1. 在根目录下创建 test 目录, 用来存放模拟的 json 数据, 在 test 目录下创建模拟的数据 data.json 文件 2.在build目录下的 dev-server.js的文件作如下 ...

  4. 浅谈 Axios 在 Vue 项目中的使用

    介绍 Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中. 特性 它主要有如下特性: 浏览器端发起XMLHttpRequests请求 Node端发起http ...

  5. 去除vue项目中的#及其ie9兼容性

    一.如何去除vue项目中访问地址的# vue2中在路由配置中添加mode(vue-cli创建的项目在src/router/index.js) export default new Router({ m ...

  6. vue 项目中当访问路由不存在的时候默认访问404页面

    前言: 在Vue项目中,当访问的页面路由不存在或错误时,页面显示为一片空白.然而,通常我们需要对访问url不存在或者错误的情况下添加默认的404页面,即not found页面. 一般的处理方法是: 在 ...

  7. vue项目中遇到的那些事。

    前言 有好几天没更新文章了.这段实际忙着做了一个vue的项目,从 19 天前开始,到今天刚好 20 天,独立完成. 做vue项目做这个项目一方面能为工作做一些准备,一方面也精进一下技术. 技术栈:vu ...

  8. scss/less语法以及在vue项目中的使用(转载)

    1.scss与less都是css的预处理器,首先我们的明白为什么要用scss与less,因为css只是一种标记语言,其中并没有函数变量之类的,所以当写复杂的样式时必然存在局限性,不灵活,而scss与l ...

  9. Vue项目中GraphQL入门学习与应用

    1.GraphQL是什么,能干什么? 正如官网所说,GraphQL是一种用于API查询的语言.Facebook 的移动应用从 2012 年就开始使用 GraphQL.GraphQL 规范于 2015 ...

  10. 转:如何在Vue项目中使用vw实现移动端适配

    https://www.w3cplus.com/mobile/vw-layout-in-vue.html 有关于移动端的适配布局一直以来都是众说纷纭,对应的解决方案也是有很多种.在<使用Flex ...

随机推荐

  1. Linux 在线安装MySQL8.0

    1.更新Linux yum yum update 2.安装wget工具(如果已经安装wget,可以跳过该步骤) yum install wget 3.使用wget下载MySQL Yum Reposit ...

  2. 【LGR-148-Div.3】洛谷基础赛 #1 & MGOI Round I

    [LGR-148-Div.3]洛谷基础赛 #1 & MGOI Round I T1 luoguP9502 『MGOI』Simple Round I | A. 魔法数字 \(100pts\) 水 ...

  3. CF1829H Don't Blame Me

    题目链接 题解 知识点:线性dp,位运算. 考虑设 \(f_{i,j}\) 表示考虑了前 \(i\) 个数字,与和为 \(j\) 的方案数.转移方程显然. 注意初值为 \(f_{0,63} = 1\) ...

  4. Python 中global 关键字理解

    Python中的global关键字,你了解吗? 前言 今天来了解下 Python 中的 global 关键字. Python变量的作用域 实战案例演示之前,先要了解下 Python 的作用域. Pyt ...

  5. StretchDIBits在一些图像尺寸下失败

    StretchDIBits用来打印图像,但是由于某种未知的原因,当图像达到特定尺寸时,它会失败. 图像数据从其他一些图像源以24位BGR格式加载到无符号int数组中.它可以在某些大小下工作,但根本无法 ...

  6. CSS之浮动Float

    前言 提到浮动,前端的小伙伴肯定都不陌生,但是随着弹性布局等等一些更好用的标准出来后,用在布局方面少了很多,当初我刚开始接触前端的时候,很习惯用浮动来给元素改变定位,当时还并不是很流行flexbox布 ...

  7. Nacos搭建单机实例

    Nacos是阿里开源的微服务架构组件,既可以用作服务注册中心,也可用作配置中心. 虽然Nacos的官方文档也有关于如何部署的说明,但是个人觉得不够详细和连续,故本文将阐述在单机环境实际搭建Nacos环 ...

  8. [超实用插件]在Visual Studio中查看EF Core查询计划

    前言 EF Core是我们.NET开发中比较常用的一款ORM框架,今天我们分享一款可以直接在Visual Studio中查看EF Core查询计划调试器可视化工具(帮助开发者分析和优化数据库查询性能) ...

  9. FFmpeg开发笔记(六):ffmpeg解码视频并使用SDL同步时间显示播放

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  10. urllib模块常用方法

    import urllib.parse ## urlparse() 对url进行解析,并对url按照一定格式进行拆分,返回一个包含6个字符串的元组(协议,位置,路径,参数,查询,判断), 可以将获得的 ...