侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

浅出Vue 错误处理机制errorCaptured、errorHandler

前端  /  管理员 发布于 6年前   453

引子

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、infoVue.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 demonstration    return this.$slots.default[0]  }})


正文

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

解读error.js源码

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

handleError、globalHandleError、invokeWithErrorHandling、logErrorhandleError

在需要捕获异常的地方调用。首先获取到报错的组件,之后递归查找当前组件的父组件,依次调用errorCaptured 方法。在遍历调用完所有 errorCaptured 方法、或 errorCaptured 方法有报错时,调用 globalHandleError 方法

globalHandleError

调用全局的 errorHandler 方法,如果 errorHandler 方法自己又报错了呢?生产环境下会使用 console.error 在控制台中输出

invokeWithErrorHandling

更好的异步错误处理,当时写这篇文章时,git history显示小右哥,一周之前敲的代码,瞬间透心凉,心飞扬

logError

判断环境,选择不同的抛错方式。非生产环境下,调用warn方法处理错误

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

/* @flow */# Vue 全局配置,也就是上面的Vue.configimport config from '../config'import { warn } from './debug'# 判断环境import { inBrowser, inWeex } from './env'# 判断是否是Promise,通过val.then === 'function' && val.catch === 'function', val !=== null && val !== undefinedimport { 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  }}



  • 上一条:
    vue中axios的使用与封装
    下一条:
    Vue.js-计算属性和class与style绑定
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 使用 Alpine.js 排序插件对元素进行排序(0个评论)
    • 在js中使用jszip + file-saver实现批量下载OSS文件功能示例(0个评论)
    • 在vue中实现父页面按钮显示子组件中的el-dialog效果(0个评论)
    • 使用mock-server实现模拟接口对接流程步骤(0个评论)
    • vue项目打包程序实现把项目打包成一个exe可执行程序(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-03
    • 2018-04
    • 2018-05
    • 2018-06
    • 2018-09
    • 2018-11
    • 2018-12
    • 2019-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2021-04
    • 2021-05
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客