primers

JavaScript itself is a weakly typed language, which is prone to errors in projects. Monitoring web page errors can help developers quickly locate problems and ensure online stability. The VUE project needs to be connected to the company’s internal monitoring platform. I didn’t know much about it before, so I decided to check out 🖼

ErrorHandler and errorCaptured are described

Document portals: errorHandler and errorCaptured

errorHandler

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

Vue.config.errorHandler = function (err, vm, info) {
  # Handle error messages and report errors
  #err Error object
  # Vue vm instances
  # 'info' is Vue specific error information, such as the lifecycle hook where the error occurred
  # only available in 2.2.0+
}
Copy the code

Version split point

  • 2.2.0 to catch errors in component lifecycle hooks. Similarly, when the hook is undefined, the caught error will be output console.error to avoid application crashes
  • As of 2.4.0, errors within Vue custom event handlers will also be caught
  • As of 2.6.0, errors thrown internally by V-ON DOM listeners will also be caught. In addition, if any overridden hook or handler returns a Promise chain (such as async function), errors from its Promise chain will also be handled

errorCaptured

Called when an error from a descendant component is caught. The hook receives three parameters: the error object, the component instance where the error occurred, and a string containing information about the source of the error. This hook can return false to prevent further propagation of the error

Error propagation rule

  • By default, if the config.errorHandler is defined globally, all errors will still be sent to it, so these errors will still be reported to a single analytic service place
  • If there are multiple errorCaptured hooks in a component’s descendant or parent slave links, they will be recalled one by one by the same error.
  • ErrorHandler If the errorCaptured hook throws an error itself, both the new error and the original caught error are sent to the global config.errorHandler. Errors thrown inside asynchronous Promises and their own errors cannot be caught
  • An errorCaptured hook returns false to prevent an error from escalating. Essentially saying “This error has been fixed and should be ignored”. It prevents errorCaptured hooks and the global config.errorHandler that are triggered by this error

ErrorHandler and errorCaptured are examples

Light talk, no action, said nothing, presented the results for you to see the official view

Mounted hook Specifies an undefined variable. Example: A mounted() {a}

  • Vue.config.errorHandler Err, VM, and info
  • Vue.config.errorHandler throws the same error, err

    The globalHandleError function has e! == err Prevents log errors twice
  • Vue.config.errorHandler throws a new Error(‘ Hello poison ‘)

  • errorCaptured (err, vm, info) => ? Boolean is similar to React error handling boundaries
<error-boundary>
  <another-component/>
</error-boundary>
Copy the code
Vue.component('ErrorBoundary', {
  data: () => ({ error: null }),
  errorCaptured (err, vm, info) {
    this.error = `${err.stack}\n\nfound in ${info} of component`
    return false
  },
  render (h) {
    if (this.error) {
      return h('pre', { style: { color: 'red' }}, this.error)
    }
    // ignoring edge cases for the sake of demonstration
    return this.$slots.default[0]
  }
})
Copy the code

The body of the

Are you a ninja ☺? Are you a ninja? Are you a ninja? Are you a ninja

Read the error. Js source code

Vue source code, exception handling logic in/SRC /core/util/error.js

HandleError, globalHandleError, invokeWithErrorHandling, logError

  • HandleError is called where exceptions need to be caught. It first captures the component that is reporting an error, then recursively searches for the parent of the current component and calls errorCaptured in turn. The globalHandleError method is called when errorCaptured methods have been called, or when errorCaptured methods report errors
  • GlobalHandleError calls the global errorHandler method. What if the errorHandler method itself fails? In production, console.error is printed in the console
  • InvokeWithErrorHandling is better for asynchronous error handling. At the time of this writing, Git History shows that the code you typed a week ago was instantly cool
  • LogError Determines the environment and selects different error throwing methods. In non-production environments, the WARN method is called to handle errors

ErrorCaptured and errorHandler are both triggered the same way, except that errorCaptured occurs first and if errorCaptured returns false, The exception message will no longer bubble up and the errorHandler method will not be called

/* @flow */
# Vue global configuration, also known as vue.config above
import config from '.. /config'
import { warn } from './debug'
# Judge the environment
import { inBrowser, inWeex } from './env'
Then === 'function' && val. Catch === 'function', val! === null && val ! == undefined
import { isPromise } from 'shared/util'
Deps tracing is disabled to avoid infinite rendering when error functions handle errors
# to solve the problems about the following problem of https://github.com/vuejs/vuex/issues/1505
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 currently reporting an error
    if (vm) {
      let cur = vm
      ErrorCaptured is first captured, then recursively searches for the parent of the current component and calls errorCaptured in turn.
      GlobalHandleError is called when errorCaptured methods have been called, or when errorCaptured methods report errors
      while ((cur = cur.$parent)) {
        const hooks = cur.$options.errorCaptured
        ErrorCaptured hook function
        if (hooks) {
        # option merge strategy, hook functions will be stored in an array
          for (let i = 0; i < hooks.length; i++) {
            If errorCaptured hooks throw errors themselves,
            Try {}catch{} and send both the new error and the original caught error to the global config.errorHandler
            # Call globalHandleError
            try {
              ErrorCaptured is executed based on whether the value is false
              Capture = true prevents errorCaptured hooks and the global config.errorHandler that are triggered by this error
              # is true capture = fale. Multiple errorCaptured hooks in a component's descendant or parent slave link are triggered 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')}}}}}The global error handler is called unless the error propagation is prohibited
    globalHandleError(err, vm, info)
  } finally {
    popTarget()
  }
}
Asynchronous error handlers
export function invokeWithErrorHandling (
  handler: Function,
  context: any,
  args: null | any[],
  vm: any,
  info: string
) {
  let res
  try {
    Select different handle execution modes based on the parameters
    res = args ? handler.apply(context, args) : handler.call(context)
    # Handle returns the result exists
    # res._isvue an flag to avoid this being observed, if the _isVue of the passed value is true (i.e. the passed value is the Vue instance itself), no new Observer instance is created
    Then === 'function' && val. Catch === 'function', val! === null && val ! == undefined
    #! Res._handled _handle is one of the internal variables of the Promise instance, which defaults to false, representing onFulfilled and onRejected
    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 occurrences of a catch in nested calls
      res._handled = true
    }
  } catch (e) {
    # Handle execution errors
    handleError(e, vm, info)
  }
  return res
}

# global error handling
function globalHandleError (err, vm, info) {
  Set handler function (default: undefined)
  # configured
  if (config.errorHandler) {
    # try{}catch{} global error handlers
    try {
      # Execute the global error handler that you set. Handle Error can do whatever you want 💗
      return config.errorHandler.call(null, err, vm, info)
    } catch (e) {
      # If the developer manually throws the same error message in the errorHandler function
      Check whether err information is equal, avoid log twice
      # If a new Error message throw Err Error(' Hello poison ') is thrown, it will be logged
      if(e ! == err) {logError(e, null, 'config.errorHandler')}}}Normal 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
  }
}
Copy the code

Happy time

The above is my simple understanding of VUE error handling, welcome your comments and exchanges, common progress, Enjoy!

Reference Documents:

Vue error API VUE error handling Promise source code analysis vue/issues/7074