background

  • Are you still bothered by dealing with Uncaught (in Promise) ReferenceError?
  • Are you still writing try catches repeatedly for exceptions?
  • Do you still write catch for every promise?
Time for one stop unified exception handling!! (For VUE projects, including VUEX)

Global exception catching

Vue.config.errorHandler = function (err, vm, info) {
  // Specifies a handler that does not catch errors during rendering and viewing of the component. When this handler is called, it gets an error message and a Vue instance.
  
  // handle error
  // 'info' is Vue specific error information, such as the lifecycle hook where the error occurred
  // Only available in 2.2.0+
}
Copy the code

Note: For exception handling, synchronous and asynchronous exceptions should be treated differently.

Vue core source code analysis

Read the source code to see how vue exposes the vue.config. errorHandler interface to the user.

Synchronization exception handling scheme

// Define an exception handling function to determine whether the user has customized Vue. Config. errorHandler.
function globalHandleError(err, vm, info) {
  if (Vue.config.errorHandler) {
    try {
      return config.errorHandler.call(null, err, vm, info)
    } catch (e) {
      logError(e, null.'config.errorHandler');
    }
  }
  logError(err, vm, info);
}
try {
  // The normally executing vue code is wrapped in a try and globalHandleError is called if there is an exception
} catch (e) {
  globalHandleError(e, vm, 'Corresponding information');
}
Copy the code

Asynchronous exception handling scheme

// Define asynchronous exception handlers that uniformly catch promises that do not themselves catch exceptions
function invokeWithErrorHandling(handler, context, args, vm, info) {
  var res;
  try {
    res = args ? handler.apply(context, args) : handler.call(context);
    if(res && ! res._isVue && isPromise(res) && ! res._handled) { res.catch(function (e) { return handleError(e, vm, info + " (Promise/async)"); });
      // Asynchronous code such as promise can be uniformly defined as promise.prototype.catch ().
      res._handled = true; }}catch (e) {
    handleError(e, vm, info);
  }
  return res
}

// All hook functions call exception handlers
function callHook(vm, hook) {
  var handlers = vm.$options[hook];
  // Add exception handling for all hooks
  var info = hook + " hook";
  if (handlers) {
    for (var i = 0, j = handlers.length; i < j; i++) {
      invokeWithErrorHandling(handlers[i], vm, null, vm, info); }}}Copy the code

Knowledge extension

The vUE interface is capable of handling synchronous exceptions and asynchronous exceptions in some hooks. For exceptions in methods that cannot be handled effectively, we can copy the asynchronous exception handling in the source code addition method and avoid writing a catch for every promise
Vue.mixin({
  beforeCreate() {
    const methods = this.$options.methods || {}
    Object.keys(methods).forEach(key= > {
      let fn = methods[key]
      this.$options.methods[key] = function (. args) {
        let ret = fn.apply(this, args)
        if (ret && typeof ret.then === 'function' && typeof ret.catch === "function") {
          return ret.catch(Vue.config.errorHandler)
        } else { // Default error handling
          return ret
        }
      }
    })
  }
})

// Vuex action also does exception unified handling, the core code is shown below
function registerActionHandle(actions) {
    Object.keys(actions).forEach(key= > {
        let fn = actions[key]
        actions[key] = function (. args) {
            let ret = fn.apply(this, args)
            if (isPromise(ret)) {
                return ret.catch(errorHandler)
            } else { // Default error handling
                return ret
            }
        }
    })
}
const registerVuex = (instance) = > {
    if (instance.$options['store']) {
        let actions = instance.$options['store'] ['_actions') | | {}if (actions) {
            let tempActions = {}
            Object.keys(actions).forEach(key= > {
                tempActions[key] = actions[key][0]
            })
            registerActionHandle(tempActions)
        }
    }
}

Copy the code

The complete code

Below is the complete code for global exception handling, packaged as a plug-in

errorPlugin.js

Global exception handling / * * * * @ param} {* error * @ param} {* * / vm

function isPromise(ret) {
    return (ret && typeof ret.then === 'function' && typeof ret.catch === "function")}const errorHandler = (error, vm, info) = > {
    console.error('Throw global exception')
    console.error(vm)
    console.error(error)
    console.error(info)
}
function registerActionHandle(actions) {
    Object.keys(actions).forEach(key= > {
        let fn = actions[key]
        actions[key] = function (. args) {
            let ret = fn.apply(this, args)
            if (isPromise(ret)) {
                return ret.catch(errorHandler)
            } else { // Default error handling
                return ret
            }
        }
    })
}
const registerVuex = (instance) = > {
    if (instance.$options['store']) {
        let actions = instance.$options['store'] ['_actions') | | {}if (actions) {
            let tempActions = {}
            Object.keys(actions).forEach(key= > {
                tempActions[key] = actions[key][0]
            })
            registerActionHandle(tempActions)
        }
    }
}
const registerVue = (instance) = > {
    if (instance.$options.methods) {
        let actions = instance.$options.methods || {}
        if (actions) {
            registerActionHandle(actions)
        }
    }
}

let GlobalError = {
    install: (Vue, options) = > {
        Global exception handling / * * * * @ param} {* error * @ param} {* * / vm
        Vue.config.errorHandler = errorHandler
        Vue.mixin({
            beforeCreate() {
                registerVue(this)
                registerVuex(this)
            }
        })
        Vue.prototype.$throw = errorHandler
    }
}

export default GlobalError

Copy the code

use

// In the import file
import ErrorPlugin from './errorPlugin'
import Vue from 'vue'
Vue.use(ErrorPlugin)
Copy the code

Write in the last

Added global exception handling to help

  • Improve code robustness
  • Reduce the collapse
  • Quick Bug location

The complete code

  • Github.com/s249359986/…

Data reference

  • Github.com/vuejs/vue/b…
  • Cn.vuejs.org/v2/api/#err…

Make code more artistic!!

About us

The front end team of Kuaigou Taxi focuses on sharing front-end technology and regularly pushes high-quality articles, which are welcome to be praised.