How do you handle errors in the vue project?

1, Error type

Any framework is a necessary capability for error handling

In Vue   In, a set of corresponding error handling rules is defined to the user, and some necessary processes are handled at the source code level.

The main error sources include:

  • Back end interface error

  • Logic error in code

2, How

Back end interface error

The response of network request is realized through the interceptor of axios, and the first layer interception is performed

apiClient.interceptors.response.use(
  response => {
    return response;
  },
  error => {
    if (error.response.status == 401) {
      router.push({ name: "Login" });
    } else {
      message.error("Error ");
      return Promise.reject(error);
    }
  }
);

Code logic problem

Global settings error handling

Set global error handling function

Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // ` info`   yes   Vue   Specific error information, such as the life cycle hook where the error is located
  //  Only in   2.2.0+   available
}

errorHandler specifies the handler function that does not catch errors during rendering and observation of the component. When this handler function is called, you can get error information and   Vue   example

However, it is worth noting that in different Vue   In version, the global   API   The scope of action will vary:

Since 2.2.0, this hook will also catch errors in the component life cycle hook. Similarly, when this hook is   undefined   When, the captured error passes   console.error   Output to avoid application collapse

Starting from 2.4.0, this hook will also catch errors inside Vue custom event handler functions

As of 2.6.0, this hook will also capture   v-on   An error thrown inside the DOM listener. In addition, if any overridden hook or processing function returns a Promise chain (such as async function), the error from its Promise chain will also be processed

Lifecycle hook

errorCaptured is a new life hook function in 2.5.0. It is called when an error from a descendant component is caught

Basic type

(err: Error, vm: Component, info: string) => ?boolean

The hook receives three parameters: the error object, the component instance where the error occurred, and a string containing the error source information. This hook can return   false   To prevent the error from continuing to propagate upward

Referring to the official website, the error propagation rules are as follows:

  • By default, if global   config.errorHandler   Defined, all errors will still be sent, so these errors will still be reported to a single analysis service

  • If there is more than one component in the inheritance or parent slave link of a component   errorCaptured   Hook, they will be recalled one by one by the same error.

  • If this   errorCaptured   If the hook throws an error, both the new error and the originally caught error will be sent to the global   config.errorHandler

  • One   errorCaptured   The hook can return   false   To prevent the error from continuing to propagate upward. In essence, it means "this mistake has been solved and should be ignored". It will prevent any other that will be aroused by this error   errorCaptured   Hook and global   config.errorHandler

Let's take an example

Define a parent component cat

Vue.component('cat', {
    template:`
        <div>
   <h1>Cat: </h1>
         <slot></slot>
        </div>`,
    props:{
        name:{
            required:true,
            type:String
        }
    },
    errorCaptured(err,vm,info) {
        console.log(`cat EC: ${err.toString()}\ninfo: ${info}`); 
        return false;
    }

});

Define a subcomponent kitten, where dontexist() is not defined. There is an error

Vue.component('kitten', {
    template:'<div><h1>Kitten: {{ dontexist() }}</h1></div>',
    props:{
        name:{
            required:true,
            type:String
        }
    }
});

Components used in pages

<div id="app" v-cloak>
    <cat name="my cat">
        <kitten></kitten>
    </cat>
</div>

The information can be captured in the errorCaptured of the parent component

cat EC: TypeError: dontexist is not a function
info: render

3, Source code analysis

Exception handling source code

Source location: / src/core/util/error.js

//  Vue   Global configuration, that is, Vue.config above
import config from '../config'
import { warn } from './debug'
//  Judgment environment
import { inBrowser, inWeex } from './env'
//  Judge whether it is Promise through val.then===  ' function'  &&  val.catch ===  ' function', val !===  null && val !==  undefined
import { isPromise } from 'shared/util'
//  When the error function handles errors, deps tracing is disabled to avoid possible infinite errors   rendering
//  Solve the following problems https://github.com/vuejs/vuex/issues/1505 Question of
import { pushTarget, popTarget } from '../observer/dep'

export function handleError (err: Error, vm: any, info: string) {
    // Deactivate deps tracking while processing error handler to avoid possible infinite rendering.
    pushTarget()
    try {
        //  vm refers to the component instance that currently reports an error
        if (vm) {
            let cur = vm
            //  First, get the error reporting component, then recursively find the parent component of the current component, and call the errorCaptured method in turn.
            //  After traversal, call all   errorCaptured   Method, or   errorCaptured   When the method reports an error, call   globalHandleError   method
            while ((cur = cur.$parent)) {
                const hooks = cur.$options.errorCaptured
                //  Determine whether there is an errorCaptured hook function
                if (hooks) {
                    //  Option, the hook function will be saved in an array
                    for (let i = 0; i < hooks.length; i++) {
                        //  If errorCaptured   The hook execution itself threw an error,
                        //  Then try{}catch {} is used to catch the error, and the new error and the originally caught error will be sent to the global config.errorHandler
                        //  Call the globalHandleError method
                        try {
                            //  Currently, errorCaptured is executed, depending on whether the returned value is false
                            //  Yes false, capture  =  true to block any other that will be aroused by this error   errorCaptured   Hook and global   config.errorHandler
                            //  Is true   capture  =  False, the inheritance of the component or multiple existing in the parent slave link   errorCaptured   Hooks will be recalled one by one by the same error
                            //  Call the corresponding hook function to handle the error
                            const capture = hooks[i].call(cur, err, vm, info) === false
                            if (capture) return
                        } catch (e) {
                            globalHandleError(e, cur, 'errorCaptured hook')
                        }
                    }
                }
            }
        }
        //  Global error handling functions are called unless upward propagation of errors is prohibited
        globalHandleError(err, vm, info)
    } finally {
        popTarget()
    }
}
//  Asynchronous error handling function
export function invokeWithErrorHandling (
handler: Function,
 context: any,
 args: null | any[],
    vm: any,
        info: string
        ) {
            let res
            try {
                //  Select different handle execution methods according to parameters
                res = args ? handler.apply(context, args) : handler.call(context)
                //  The result returned by handle does not exist
                //  res._isVue   an   flag   to   avoid   this   being   observed, if the value is passed in_ When isvue is true (that is, the value passed in is the Vue instance itself), no new observer instance will be created
                // isPromise(res)   Judge val.then===  ' function'  &&  val.catch ===  ' function', val !===  null && val !==  undefined
                // ! res._handled   _ handle is Promise   One of the internal variables of the instance, which is false by default, represents whether onfulfilled and onrejected are processed
                if (res && !res._isVue && isPromise(res) && !res._handled) {
                    res.catch(e => handleError(e, vm, info + ` (Promise/async)`))
                    // avoid catch triggering multiple times when nested calls
                    //  Avoid multiple trigger of catch during nested call
                    res._handled = true
                }
            } catch (e) {
                //  Processing execution error
                handleError(e, vm, info)
            }
            return res
        }

//Global error handling
function globalHandleError (err, vm, info) {
    //  Get the global configuration and judge whether to set the processing function. The default is undefined
    //  Configured
    if (config.errorHandler) {
        //  try{}catch{}   Global error handling function
        try {
            //  Execute the set global error handling function, handle   error   Do whatever you want 💗
            return config.errorHandler.call(null, err, vm, info)
        } catch (e) {
            //  If the developer manually throws the same error message throw in the errorHandler function   err
            //  Judge whether the err information is equal and avoid log twice
            //  If a new error message throw is thrown   err   Error('Hello poison ') will be output together with log
            if (e !== err) {
                logError(e, null, 'config.errorHandler')
            }
        }
    }
    //  General log output is not configured
    logError(err, vm, info)
}

//  Error output function
function logError (err, vm, info) {
    if (process.env.NODE_ENV !== 'production') {
        warn(`Error in ${info}: "${err.toString()}"`, vm)
    }
    /* istanbul ignore else */
    if ((inBrowser || inWeex) && typeof console !== 'undefined') {
        console.error(err)
    } else {
        throw err
    }
}

Summary

  • handleError is called where exceptions need to be caught. First, get the component reporting an error, then recursively find the parent component of the current component, and call errorcaptured in turn   Method after traversal   errorCaptured   Method or   errorCaptured   When the method reports an error, call   globalHandleError   method

  • globalHandleError calls the global   errorHandler   Method, and then judge the environment through logError to output error information

  • invokeWithErrorHandling handles asynchronous error messages better

  • logError judges the environment and selects different error throwing methods. In a non production environment, call the warn method to handle errors

Tags: Javascript Front-end Vue.js

Posted on Mon, 01 Nov 2021 00:59:12 -0400 by delayedinsanity