共计 3363 个字符,预计需要花费 9 分钟才能阅读完成。
前言
在之前的我的项目中,须要做全局谬误的收集和上报,最初有个头疼的问题就是 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 不胜感激!