In the previous project, we needed to collect and report global errors. Finally, we had a headache that the asynchronous errors in Vue Watch could not be reported to errorHandler. Then one day when I read the Vue code again, I found that Vue had fixed this problem in version 2.6.13. !!!!!

example

You can switch the Vue version number to see the effect, and you will see that <= 2.6.12 watch does not catch asynchronous errors

 

    <button @click=’num++’>{{ num }}

 

Copy the code

How is Vue solved

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

// The callback function in Watcher is the same as the following

    const watcher = new Watcher(vm, expOrFn, cb, options)

    if (options.immediate) {

      try {

// Execute the callback directly

        cb.call(vm, watcher.value)

      } catch (error) {

        handleError(error, vm, callback for immediate watcher "${watcher.expression}")

      }

    }

    return function unwatchFn () {

      watcher.teardown()

    }

}

Copy the code

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

// The callback function in Watcher is the same as the following

    const watcher = new Watcher(vm, expOrFn, cb, options)

    if (options.immediate) {

      const info = callback for immediate watcher "${watcher.expression}"

      pushTarget()

// Use this function to execute the callback function

      invokeWithErrorHandling(cb, vm, [watcher.value], vm, info)

      popTarget()

    }

    return function unwatchFn () {

      watcher.teardown()

    }

}

Copy the code

Compare the version

The difference is that the callback is executed by invokeWithErrorHandling. If it is a promise, it will be caught and reported by handleError. Front end of the training

 

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

}

Copy the code

thinking

One might ask, why don’t you try and catch your own error message, or what does that do?

Try and catch yourself. It’s a lot of repetition.

This is a small fix for Vue, but for an online project, failing to report all of your bugs can affect the user experience, lead to user churn, and even cost the company property.

How does Vue collect and report errors

For us developers, it is better not to manually report errors, which will lead to a lot of repetitive work. It is better to just focus on our normal business logic, while for Vue project, Vue will automatically report our errors. We just need to make sure that we write in a certain way so that the errors will not be lost.

The first step

The only place we need to report errors globally is Vue errorHandler. Vue will report all errors to this function. You can either apply Sentry directly or call the background error reporting interface in this function.

The second step

We have identified where the error was reported, and what we need to do is make sure that all errors are caught by the Vue. For synchronous tasks, errors are caught directly, and for asynchronous tasks, we have to use a certain way of writing.

Asynchronous error

The most common part of our project is interacting with the background, as follows

Writing a

This is one of the most common things I’ve seen in a project. Once we use THEN for asynchronous tasks, it means that our errors will not be caught by the Vue. If we have an error in the THEN callback, we have to write a.catch at the end to catch the error in the THEN callback. This way of writing adds a lot of work for us developers.

 

mounted() {

// No errors will be caught

    this.getData()

},

methods: {

    getData() {

        http.get(‘xxx’).then(data => {

            // xxx

        }, error => {

// Can only report asynchronous errors

        })

    }

}

Copy the code

Write two

We can just replace our then with async await and all errors will be caught and much cleaner

 

async mounted() {

Async errors can be caught with await

    await this.getData()

},

methods: {

    async getData() {

        const data = await http.get(‘xxx’)

        // xxx

    }

}

Copy the code

How to ensure that everyone uses async syntax development

If you have a project where everyone can follow this, you don’t have to look further.

 

For the development project, the developer is not controllable, the coding style is also changeable, and even if you remember which way to write, there will be negligence in the actual development, or can use tools to solve the problem without verbal constraints.

With the help of eslint

Eslint-plugin-leon-rule: Eslint-plugin-leon-rule: Eslint-plugin-leon-rule: eslint-plugin-leon-rule: eslint-plugin-leon-rule: eslint-plugin-leon-rule: