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