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