前言
在之前的我的项目中,须要做全局谬误的收集和上报,最初有个头疼的问题就是 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 不胜感激!