引子

JavaScript本身是一个弱类型语言,项目中容易发生错误,做好网页错误监控,能帮助开发者迅速定位问题,保证线上稳定。
vue项目需接入公司内部监控平台,本人之前vue errorHooks不甚了解, 决定探一探?

介绍 errorHandler、errorCaptured

文档传送门: errorHandler、errorCaptured

errorHandler

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

Vue.config.errorHandler = function (err, vm, info) {#处理错误信息, 进行错误上报#err错误对象#vm Vue实例#`info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子#只在 2.2.0+ 可用
}
复制代码

版本分割点

  • 2.2.0 起,捕获组件生命周期钩子里的错误。同样的,当这个钩子是 undefined 时,被捕获的错误会通过 console.error 输出而避免应用崩溃
  • 2.4.0 起,也会捕获 Vue 自定义事件处理函数内部的错误
  • 2.6.0 起,也会捕获 v-on DOM 监听器内部抛出的错误。另外,如果任何被覆盖的钩子或处理函数返回一个 Promise 链 (例如 async 函数),则来自其 Promise 链的错误也会被处理

errorCaptured

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

错误传播规则

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

错误信息示例 errorHandler、errorCaptured

光说不练,说了白干,呈上结果供各位看官老爷查看

mounted hook 写入未定义的变量,例如:a
mounted() { a }

  • Vue.config.errorHandler err、vm、info
  • Vue.config.errorHandler 抛出同样的错误 throw err
    globalHandleError函数有 e !== err 判断防止log两次错误
  • Vue.config.errorHandler 抛出新的错误 throw new Error('你好毒')
  • errorCaptured (err, vm, info) => ?Boolean 类似于React 错误处理边界
<error-boundary><another-component/>
</error-boundary>
复制代码
Vue.component('ErrorBoundary', {data: () => ({ error: null }),errorCaptured (err, vm, info) {this.error = `${err.stack}\n\nfound in ${info} of component`return false},render (h) {if (this.error) {return h('pre', { style: { color: 'red' }}, this.error)}// ignoring edge cases for the sake of demonstrationreturn this.$slots.default[0]}
})
复制代码

正文

copy 半天官网文档,你是copy忍者吗☺,各位看官老爷,请往下面看,注意自己使用时的Vue版本,避免err抓取不到?

解读error.js源码

Vue 源码中,异常处理的逻辑放在 /src/core/util/error.js 中

handleError、globalHandleError、invokeWithErrorHandling、logError

  • handleError
    在需要捕获异常的地方调用。首先获取到报错的组件,之后递归查找当前组件的父组件,依次调用errorCaptured 方法。在遍历调用完所有 errorCaptured 方法、或 errorCaptured 方法有报错时,调用 globalHandleError 方法
  • globalHandleError
    调用全局的 errorHandler 方法,如果 errorHandler 方法自己又报错了呢?生产环境下会使用 console.error 在控制台中输出
  • invokeWithErrorHandling 更好的异步错误处理,当时写这篇文章时,git history显示小右哥,一周之前敲的代码,瞬间透心凉,心飞扬
  • logError
    判断环境,选择不同的抛错方式。非生产环境下,调用warn方法处理错误

errorCaptured 和 errorHandler 的触发时机都是相同的,不同的是 errorCaptured 发生在前,且如果某个组件的 errorCaptured 方法返回了 false,那么这个异常信息不会再向上冒泡也不会再调用 errorHandler 方法

/* @flow */
# 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) === falseif (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 restry {# 根据参数选择不同的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}
}
复制代码

欢乐时光

以上是本人对vue 错误处理的浅显理解,欢迎大家评论交流,共同进步, enjoy !

参考文档:

vue错误api
vue错误处理
Promise源码剖析
vue/issues/7074

转载于:https://juejin.im/post/5c8e139f6fb9a0710f47d949

浅出Vue 错误处理机制errorCaptured、errorHandler相关推荐

  1. Vue.js@2.6.10更新内置错误处机制,Fundebug同步支持相应错误监控

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: Fundebug 的 JavaScript 错误监控插件同步支持 Vue.js 异步错误监控. Vue.js 从诞生至 ...

  2. 浅入深出Vue:环境搭建

    浅入深出Vue:环境搭建 工欲善其事必先利其器,该搭建我们的环境了. 安装NPM 所有工具的下载地址都可以在导航篇中找到,这里我们下载的是最新版本的NodeJS Windows安装程序 下载下来后,直 ...

  3. [科普]浅入浅出Liunx Shellcode

    创建时间:2008-05-13 文章属性:原创 文章提交: pr0cess  (pr0cess_at_cnbct.org) 浅入浅出Liunx Shellcode /*---------------- ...

  4. 浅入浅出深度学习理论实践

    全文共9284个字,40张图,预计阅读时间30分钟. 前言 之前在知乎上看到这么一个问题:在实际业务里,在工作中有什么用得到深度学习的例子么?用到 GPU 了么?,回头看了一下自己写了这么多东西一直围 ...

  5. Python-Level1-day16:异常处理try-exceptraise语句,for迭代原理,深入手写创建迭代器;yield浅出使用生成器

    作业 1. 三合一 2. 当天练习独立完成 3. 将员工管理系统分为4个模块employee_system.py ​ 4. (选做)完成2048上下移动函数-- 自定义矩阵转置函数,实现行列颠倒-- ...

  6. Go语言的错误异常处理机制及其应用

    一.背景 在日常编写golang程序或阅读别人的golang代码时,我们总会看到如下的一堆代码块: xx, err = func(xx) if err != nil {//do sth. to tac ...

  7. .net错误处理机制

    .net错误处理机制 让我们想想,ASP.NET为我们提供了几种错误处理机制?如果同时使用他们是不是有一定的优先级?.NET提供了四种错误处理机制,它们有一定的优先级顺序:Page_Error事件&g ...

  8. 浅谈JavaScript错误

    本文主要从前端开发者的角度谈一谈大多数前端开发者都会遇到的js错误,对错误产生的原因.发生阶段,以及如何应对错误进行分析.归纳和总结,希望得到一些有益的结论用来指导日常开发工作. 概念辨析 错误(Er ...

  9. golang错误处理机制(异常处理)

    看一段代码,引入错误处理 对上面代码的总结: 在默认情况下,当发生错误后(panic) ,程序就会退出(崩溃.) 如果我们希望:当发生错误后,可以捕获到错误,并进行处理,保证程序可以继续执行.还可 以 ...

最新文章

  1. 《深入理解Nginx:模块开发与架构解析》一1.2 为什么选择Nginx
  2. python基础语法合集-python常用语法合集
  3. 001_Layout布局
  4. CSDN转载别人文章的详细步骤
  5. dosbox中的bebug指令
  6. 政策表达式截取json_json格式数据如何提取指定中文字符串。
  7. knn人脸识别判断_测试使用K-最近邻(kNN)算法的30个问题
  8. 如何让多文本内容只显示一行,其余用省略号来显示
  9. 可达龙博客的第一篇文
  10. 二维数组各行求和_JS数组reduce()方法详解及高级技巧
  11. 用R语言实现信息度量
  12. Django项目详解2——动态响应的web应用
  13. 优化计算机组策略,Windows 10神州网信版优化
  14. 怎样修改计算机用户文件名,win10修改用用户文件夹名字怎么操作_win10更改用户文件夹名称方法...
  15. 二叉树的性质及其创建
  16. 如何才能成为数字IC后端ECO专家?
  17. 37互娱java待遇,37互娱现场java一面
  18. 苹果6s出现连接不上服务器未响应,苹果6s的蜂窝移动数据打开没反应怎么办
  19. 现在有多少老婆不上班,全靠男人一个人赚钱养家的,过得怎么样?
  20. 鼻炎舒宁治过敏性鼻炎

热门文章

  1. Spark源码系列(四)图解作业生命周期
  2. “Could not change executable permissions on the application”的原因和解决方法
  3. shell 将两行内容合并到同一行
  4. 【PetShop 4.0学习】4.数据库结构
  5. Your password has expired. To log in you must change it using a client that supports expired pass...
  6. ceph rbd resize之后文件系统的调节
  7. Java可变参数 Python可变参数 Scala可变参数
  8. Macaca基础原理解析
  9. 河神,不用砍死那个天秤座的男孩了
  10. 如何提高PHP代码的质量?第一部分 自动化工具