前言
在之前的我的项目中,须要做全局谬误的收集和上报,最初有个头疼的问题就是 Vue watch 中的异步谬误无奈上报到 errorHandler 外面,而后在某一天我再次浏览 Vue 代码的时候,发现他在 2.6.13 版本上修复了这个问题,开心!!!
例子
大家能够切换 Vue 的版本号,来看看成果,你会发现 <= 2.6.12 版本的 watch 都不会捕捉到异步谬误
<!-- vue 2.6.12 --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script><div id="app"> <button @click='num++'>{{ num }}</button></div><script> Vue.config.errorHandler = (err, vm, info) => { console.log('收集到谬误:', err) } new Vue({ el: '#app', data: { num: 100 }, watch: { async num() { // 加 await 是为了捕捉异步谬误 await this.errorFnc() } }, methods: { errorFnc() { return new Promise((resolve, reject) => { reject('promise 谬误') }) }, // 或者 async 函数 // async errorFnc() { // throw 'async 谬误' // }, } })</script>复制代码
Vue 是如何解决的
2.6.12
Vue.prototype.$watch = function ( expOrFn: string | Function, cb: any, options?: Object): Function { const vm: Component = this if (isPlainObject(cb)) { return createWatcher(vm, expOrFn, cb, options) } options = options || {} options.user = true // Watcher 外面执行回调函数和上面一样,就不贴代码了 const watcher = new Watcher(vm, expOrFn, cb, options) if (options.immediate) { try { // 间接执行回调函数 cb.call(vm, watcher.value) } catch (error) { handleError(error, vm, `callback for immediate watcher "${watcher.expression}"`) } } return function unwatchFn () { watcher.teardown() }}复制代码
2.6.13
Vue.prototype.$watch = function ( expOrFn: string | Function, cb: any, options?: Object): Function { const vm: Component = this if (isPlainObject(cb)) { return createWatcher(vm, expOrFn, cb, options) } options = options || {} options.user = true // Watcher 外面执行回调函数和上面一样,就不贴代码了 const watcher = new Watcher(vm, expOrFn, cb, options) if (options.immediate) { const info = `callback for immediate watcher "${watcher.expression}"` pushTarget() // 用该函数去执行回调函数 invokeWithErrorHandling(cb, vm, [watcher.value], vm, info) popTarget() } return function unwatchFn () { watcher.teardown() }}复制代码
比照版本
咱们发现两个版本不同的是执行回调函数的形式变了,通过 invokeWithErrorHandling 执行回调函数,如果是 promise 的话会被 catch,从而被 handleError 报告下来。
export function invokeWithErrorHandling ( handler: Function, context: any, args: null | any[], vm: any, info: string) { let res try { res = args ? handler.apply(context, args) : handler.call(context) if (res && !res._isVue && isPromise(res) && !res._handled) { res.catch(e => handleError(e, vm, info + ` (Promise/async)`)) // issue #9511 // avoid catch triggering multiple times when nested calls res._handled = true } } catch (e) { handleError(e, vm, info) } return res}复制代码
思考
有人可能会问,为什么不 try catch 本人上报错误信息,或者这个有什么用?
本人 try catch,反复工作量极大。
对 Vue 来说这个是一个很小的修复,但对于一个线上我的项目来说,如果无奈上报你的所有谬误,那么有些中央就可能会影响到用户体验,产生用户的散失,甚至让公司财产损失。
Vue 如何进行谬误收集和上报
对于咱们开发者来说,最好是不必手动上报谬误,这会带来很多重复性的工作,咱们最好只用关注咱们的失常的业务逻辑,而对于 Vue 工程来说,Vue 会主动上报咱们的谬误,咱们只有保障肯定的写法,谬误就不会失落。
第一步
咱们全局只须要一个上报谬误的中央,那就是 Vue 的 errorHandler,Vue 会把所有谬误上报到这个函数,你能够间接利用 sentry,或者在这个函数外面调用后盾的谬误上报接口。
第二步
咱们确定了上报谬误的中央,上面要做的就是保障所有谬误能被 Vue 捕捉到,同步工作的谬误会被间接捕捉,而异步工作的谬误,咱们必须应用肯定的写法。
异步谬误
我的项目中咱们最多的是和后盾交互,如下
写法一
这个是我在我的项目中见的最多的写法,一旦应用了 then 来解决异步工作,就意味着咱们的谬误不会被 Vue 捕捉,如果咱们 then 回调函数外面呈现了谬误,咱们还得在最初面写一个 .catch 来捕捉 then 回调函数外面的谬误,这种写法给咱们开发者加大了很多的工作量。
mounted() { // 不会捕捉到谬误 this.getData()},methods: { getData() { http.get('xxx').then(data => { // xxx }, error => { // 只能本人上报异步谬误 }) }}复制代码
写法二
咱们只用换成 async await 来代替咱们 then 的写法,所有谬误就会被捕捉到,而且更加简洁
async mounted() { // 应用 await 能够捕捉到异步谬误 await this.getData()},methods: { async getData() { const data = await http.get('xxx') // xxx }}复制代码
如何保障所有人应用 async 语法开发
如果你的我的项目中大家都能够恪守这种写法,那就不必往下看了。
对于开发我的项目来说,开发者是不可控的,编码格调也是变幻无穷,而且就算记住了哪种写法,在理论开发的时候也会有忽略,还是能用工具解决的就不必口头去束缚。
借助 eslint
基于 eslint 咱们能够很轻松制订一套规定,但有一些规定是没有的,就须要咱们本人开发,我对下面 async 语法的束缚写了一个插件:eslint-plugin-leon-rule,大家能够参考下源码或者应用。
最初
如果你感觉此文对你有一丁点帮忙,点个赞。或者能够退出我的开发交换群:1025263163互相学习,咱们会有业余的技术答疑解惑
如果你感觉这篇文章对你有点用的话,麻烦请给咱们的开源我的项目点点star: https://gitee.com/ZhongBangKeJi/CRMEB不胜感激 !