优雅的处理vue项目异常实战记录


Posted in Javascript onJune 05, 2019

背景

  • 你还在为处理Uncaught (in promise) ReferenceError烦恼吗?
  • 你还在为捕获异常反复的写try catch吗?
  • 你还在为每一个promise写catch吗?

是时候一站式统一处理异常!!!(针对vue项目)

全局异常捕获

Vue.config.errorHandler = function (err, vm, info) {
 // 指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。
 
 // handle error
 // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
 // 只在 2.2.0+ 可用 
}

注意:面对异常处理,同步异常和异步异常应该区别对待分别处理。

vue核心源码剖析

通过阅读源码看一下vue是如何将Vue.config.errorHandler接口暴露给使用者。

同步异常处理方案

// 定义异常处理函数,判断用户是否自定义Vue.config.errorHandler,定义则直接调用,未定义执行vue本身异常处理。
function globalHandleError(err, vm, info) {
 if (Vue.config.errorHandler) {
  try {
   return config.errorHandler.call(null, err, vm, info)
  } catch (e) {
   logError(e, null, 'config.errorHandler');
  }
 }
 logError(err, vm, info);
}
try {
 // vue正常执行代码被包裹在try内,有异常会调用globalHandleError
} catch (e) {
 globalHandleError(e, vm, '对应信息');
}

异步异常处理方案

// 定义异步异常处理函数,对于自身没有捕获异常的promise统一执行catch
function invokeWithErrorHandling(
 handler,
 context,
 args,
 vm,
 info
) {
 var res;
 try {
  res = args ? handler.apply(context, args) : handler.call(context);
  if (res && !res._isVue && isPromise(res) && !res._handled) {
   res.catch(function (e) { return handleError(e, vm, info + " (Promise/async)"); });
   // 异步代码例如promise可以统一为其定义Promise.prototype.catch()方法。
   res._handled = true;
  }
 } catch (e) {
  handleError(e, vm, info);
 }
 return res
}

// 所有的钩子函数调用异常处理函数
function callHook(vm, hook) {
 var handlers = vm.$options[hook];
 // 为所有钩子增加异常处理
 var info = hook + " hook";
 if (handlers) {
  for (var i = 0, j = handlers.length; i < j; i++) {
   invokeWithErrorHandling(handlers[i], vm, null, vm, info);
  }
 }
}

知识延伸

// vue接口是能处理同步异常以及部分钩子中的异步异常,对于方法中的异常无法有效处理,我们可以仿照源码增加方式中的异步异常处理,避免为每一个promise写catch
Vue.mixin({
 beforeCreate() {
  const methods = this.$options.methods || {}
  Object.keys(methods).forEach(key => {
   let fn = methods[key]
   this.$options.methods[key] = function (...args) {
    let ret = fn.apply(this, args)
    if (ret && typeof ret.then === 'function' && typeof ret.catch === "function") {
     return ret.catch(Vue.config.errorHandler)
    } else { // 默认错误处理
     return ret
    }
   }
  })
 }
})

完整代码

下面是全局处理异常的完整代码,已经封装成一个插件

errorPlugin.js

/**
 * 全局异常处理
 * @param {
 * } error 
 * @param {*} vm 
 */
const errorHandler = (error, vm, info) => {
 console.error('抛出全局异常')
 console.error(vm)
 console.error(error)
 console.error(info)
}
let GlobalError = {
 install: (Vue, options) => {
 /**
  * 全局异常处理
  * @param {
  * } error 
  * @param {*} vm 
  */
  Vue.config.errorHandler = errorHandler
  Vue.mixin({
   beforeCreate() {
    const methods = this.$options.methods || {}
    Object.keys(methods).forEach(key => {
     let fn = methods[key]
     this.$options.methods[key] = function (...args) {
      let ret = fn.apply(this, args)
      if (ret && typeof ret.then === 'function' && typeof ret.catch === "function") {
       return ret.catch(errorHandler)
      } else { // 默认错误处理
       return ret
      }
     }
    })
   }
  })
  Vue.prototype.$throw = errorHandler
 }
}
export default GlobalError

使用

// 在入口文件中引入
import ErrorPlugin from './errorPlugin'
import Vue from 'vue'
Vue.use(ErrorPlugin)

写在最后

增加全局异常处理有助于

  • 提高代码健壮性
  • 减少崩溃
  • 快速定位bug

资料参考

  • github.com/vuejs/vue/b…
  • cn.vuejs.org/v2/api/#err…

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
超棒的javascript页面顶部卷动广告效果
Dec 01 Javascript
JavaScript创建对象的写法
Aug 29 Javascript
JS实现图片无间断滚动代码汇总
Jul 30 Javascript
JS控制网页动态生成任意行列数表格的方法
Mar 09 Javascript
详解JavaScript中循环控制语句的用法
Jun 03 Javascript
jquery实现手风琴效果
Nov 20 Javascript
快速学习AngularJs HTTP响应拦截器
Dec 31 Javascript
jq实现左滑显示删除按钮,点击删除实现删除数据功能(推荐)
Aug 23 Javascript
vue Render中slots的使用的实例代码
Jul 19 Javascript
layui table设置某一行的字体颜色方法
Sep 05 Javascript
JS实现数据动态渲染的竖向步骤条
Jun 24 Javascript
vue-drawer-layout实现手势滑出菜单栏
Nov 19 Vue.js
原生JS使用Canvas实现拖拽式绘图功能
Jun 05 #Javascript
Node.js 路由的实现方法
Jun 05 #Javascript
JS实现动态添加外部js、css到head标签的方法
Jun 05 #Javascript
JS函数动态传递参数的方法分析【基于arguments对象】
Jun 05 #Javascript
jQuery操作cookie的示例代码
Jun 05 #jQuery
JS实现从对象获取对象中单个键值的方法示例
Jun 05 #Javascript
微信小程序如何实现全局重新加载
Jun 05 #Javascript
You might like
destoon出现验证码不显示时的紧急处理方法
2014/08/22 PHP
php通过array_merge()函数合并关联和非关联数组的方法
2015/03/18 PHP
yii2项目实战之restful api授权验证详解
2017/05/20 PHP
有关js的变量作用域和this指针的讨论
2010/12/16 Javascript
js弹出层之1:JQuery.Boxy (二)
2011/10/06 Javascript
javascript检测页面是否缩放的小例子
2013/05/16 Javascript
JQuery 使用attr方法实现下拉列表选中
2014/10/13 Javascript
js实现点击左右按钮轮播图片效果实例
2015/01/29 Javascript
javascript实现表格增删改操作实例详解
2015/05/15 Javascript
jquery带动画效果幻灯片特效代码
2015/08/27 Javascript
Sort()函数的多种用法
2016/03/20 Javascript
ES6所改良的javascript“缺陷”问题
2016/08/23 Javascript
关于jQuery库冲突的完美解决办法
2017/05/20 jQuery
vue 实现 ios 原生picker 效果及实现思路解析
2017/12/06 Javascript
webpack v4 从dev到prd的方法
2018/04/02 Javascript
基于vue-element组件实现音乐播放器功能
2018/05/06 Javascript
vue监听对象及对象属性问题
2018/08/20 Javascript
jQuery实现简单的Ajax调用功能示例
2019/02/15 jQuery
vue实现带过渡效果的下拉菜单功能
2020/02/19 Javascript
详解Python中的__init__和__new__
2014/03/12 Python
python+Django+apache的配置方法详解
2016/06/01 Python
对django中render()与render_to_response()的区别详解
2018/10/16 Python
使用django实现一个代码发布系统
2019/07/18 Python
如何利用Python开发一个简单的猜数字游戏
2019/09/22 Python
使用python实现数组、链表、队列、栈的方法
2019/12/20 Python
世界上最大的网络主机公司:1&1
2016/10/12 全球购物
美国瑜伽服装和装备购物网站:Mukha Yoga
2019/02/22 全球购物
法国床上用品商店:La Compagnie du lit
2019/12/26 全球购物
新加坡鲜花速递/新加坡网上花店:Ferns N Petals
2020/08/29 全球购物
网上常见的一份Linux面试题(多项选择部分)
2015/02/07 面试题
2013的个人自我评价
2013/12/26 职场文书
班子四风对照检查材料
2014/08/21 职场文书
2014年班组工作总结
2014/11/20 职场文书
邀请函范文
2015/02/02 职场文书
毕业生捐书活动倡议书
2015/04/27 职场文书
转变工作作风心得体会
2016/01/23 职场文书