Введение
JavaScript сам по себе является языком со слабой типизацией, и в проектах могут возникать ошибки. Качественный мониторинг ошибок веб-страниц может помочь разработчикам быстро обнаружить проблемы и обеспечить стабильность работы в сети.
Проект vue нужно подключить к внутренней платформе мониторинга компании, раньше я мало что знал о vue errorHooks, поэтому решил изучить его🖼
Представляем обработчик ошибок, errorCaptured
Портал документов:errorHandler,errorCaptured
errorHandler
Указывает обработчик необработанных ошибок во время рендеринга и просмотра компонента. Когда этот обработчик вызывается, вы можете получить сообщение об ошибке и экземпляр Vue.
Vue.config.errorHandler = function (err, vm, info) {
#处理错误信息, 进行错误上报
#err错误对象
#vm Vue实例
#`info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
#只在 2.2.0+ 可用
}
Точка разделения версии
- Начиная с версии 2.2.0, ловите ошибки в обработчиках жизненного цикла компонентов. Кроме того, когда этот хук не определен, пойманная ошибка будет выводиться через console.error, чтобы избежать сбоя приложения.
- Начиная с версии 2.4.0, также перехватываются ошибки внутри пользовательских обработчиков событий Vue.
- Начиная с версии 2.6.0, также перехватываются ошибки, возникающие внутри прослушивателя v-on DOM. Кроме того, если какой-либо переопределенный хук или обработчик возвращает цепочку промисов (например, асинхронную функцию), ошибки из этой цепочки промисов также будут обрабатываться.
errorCaptured
Вызывается при обнаружении ошибки от компонента-потомка. Этот хук получает три параметра: объект ошибки, экземпляр компонента, в котором произошла ошибка, и строку, содержащую информацию об источнике ошибки. Этот хук может возвращать false, чтобы остановить распространение ошибки.
Правила распространения ошибок
- По умолчанию, если определен глобальный config.errorHandler, все ошибки все равно будут отправляться в него, поэтому эти ошибки все равно будут сообщаться в единую службу анализа.
- Если несколько хуков ErrorCaptured в наследовании компонента или родительской ведомой ссылки, они будут вызваны одной и той же ошибкой.
- Если сам хук errorCaptured выдает ошибку, новая ошибка и первоначально перехваченная ошибка будут отправлены в глобальный config.errorHandler, который не может перехватить ошибку, выброшенную внутри асинхронного обещания, и свою собственную ошибку.
- Хук errorCaptured может возвращать false, чтобы предотвратить распространение ошибок. По сути говоря, «эта ошибка была исправлена и ее следует игнорировать». Он заблокирует любые другие хуки errorCaptured и глобальный config.errorHandler, которые будут вызваны этой ошибкой.
Пример сообщения об ошибке errorHandler, errorCaptured
Просто говорите, а не тренируйтесь, болтайте впустую и представьте результаты на проверку судьям.
установленный хук записывает в неопределенные переменные, например:
mounted() { a }
- Vue.config.Errorhandler Ошибка, ВМ, Информация
- Vue.config.errorHandler выдает ту же ошибку.
Функция globalHandleError имеет оценку e !== err для предотвращения двух ошибок в журнале. - Vue.config.errorHandler выдает новую ошибку throw new Error («Привет, яд»)
- errorCaptured (err, vm, info) => ?Boolean аналогично границам обработки ошибок React
<error-boundary>
<another-component/>
</error-boundary>
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]
}
})
текст
Скопируйте документ официального сайта на долгое время, вы копирующий ниндзя☺, господа, пожалуйста, прочитайте ниже, обратите внимание на версию Vue, которую вы используете, чтобы не ошибиться, не имея возможности ее захватить🖤
Интерпретация исходного кода error.js
В исходном коде Vue логика обработки исключений размещена в /src/core/util/error.js.
handleError, globalHandleError, invokeWithErrorHandling, logError
- handleError
Вызывается там, где необходимо перехватывать исключения. Сначала получите компонент, сообщивший об ошибке, затем рекурсивно найдите родительский компонент текущего компонента и, в свою очередь, вызовите метод errorCaptured. После обхода и вызова всех методов errorCaptured или когда методы errorCaptured сообщают об ошибке, вызовите метод globalHandleError. - globalHandleError
Вызвать глобальный метод errorHandler Что делать, если метод errorHandler сам сообщает об ошибке? В производственной среде console.error будет использоваться для вывода в консоль. - invokeWithErrorHandling Улучшенная асинхронная обработка ошибок.На момент написания этой статьи история git показала, что брат Сяо Ю, код, который он набрал неделю назад, был моментально крут и сердечен
- logError
Оценивайте окружающую среду и выбирайте разные способы выбрасывания ошибок. В непроизводственной среде вызовите метод warn для обработки ошибок.
Время срабатывания errorCaptured и errorHandler одинаково, разница в том, что errorCaptured происходит раньше, и если метод errorCaptured компонента возвращает false, то информация об исключении не будет всплывать и не будет снова вызывать метод errorHandler.
/* @flow */
# Vue 全局配置,也就是上面的Vue.config
import config from '../config'
import { warn } from './debug'
# 判断环境
import { inBrowser, inWeex } from './env'
# 判断是否是Promise,通过val.then === 'function' && val.catch === 'function', val !=== null && val !== undefined
import { isPromise } from 'shared/util'
# 当错误函数处理错误时,停用deps跟踪以避免可能出现的infinite rendering
# 解决以下出现的问题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指当前报错的组件实例
if (vm) {
let cur = vm
# 首先获取到报错的组件,之后递归查找当前组件的父组件,依次调用errorCaptured 方法。
# 在遍历调用完所有 errorCaptured 方法、或 errorCaptured 方法有报错时,调用 globalHandleError 方法
while ((cur = cur.$parent)) {
const hooks = cur.$options.errorCaptured
# 判断是否存在errorCaptured钩子函数
if (hooks) {
# 选项合并的策略,钩子函数会被保存在一个数组中
for (let i = 0; i < hooks.length; i++) {
# 如果errorCaptured 钩子执行自身抛出了错误,
# 则用try{}catch{}捕获错误,将这个新错误和原本被捕获的错误都会发送给全局的config.errorHandler
# 调用globalHandleError方法
try {
# 当前errorCaptured执行,根据返回是否是false值
# 是false,capture = true,阻止其它任何会被这个错误唤起的 errorCaptured 钩子和全局的 config.errorHandler
# 是true capture = fale,组件的继承或父级从属链路中存在的多个 errorCaptured 钩子,会被相同的错误逐个唤起
# 调用对应的钩子函数,处理错误
const capture = hooks[i].call(cur, err, vm, info) === false
if (capture) return
} catch (e) {
globalHandleError(e, cur, 'errorCaptured hook')
}
}
}
}
}
# 除非禁止错误向上传播,否则都会调用全局的错误处理函数
globalHandleError(err, vm, info)
} finally {
popTarget()
}
}
# 异步错误处理函数
export function invokeWithErrorHandling (
handler: Function,
context: any,
args: null | any[],
vm: any,
info: string
) {
let res
try {
# 根据参数选择不同的handle执行方式
res = args ? handler.apply(context, args) : handler.call(context)
# handle返回结果存在
# res._isVue an flag to avoid this being observed,如果传入值的_isVue为ture时(即传入的值是Vue实例本身)不会新建observer实例
# isPromise(res) 判断val.then === 'function' && val.catch === 'function', val !=== null && val !== undefined
# !res._handled _handle是Promise 实例的内部变量之一,默认是false,代表onFulfilled,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
# 避免嵌套调用时catch多次的触发
res._handled = true
}
} catch (e) {
# 处理执行错误
handleError(e, vm, info)
}
return res
}
#全局错误处理
function globalHandleError (err, vm, info) {
# 获取全局配置,判断是否设置处理函数,默认undefined
# 已配置
if (config.errorHandler) {
# try{}catch{} 住全局错误处理函数
try {
# 执行设置的全局错误处理函数,handle error 想干啥就干啥💗
return config.errorHandler.call(null, err, vm, info)
} catch (e) {
# 如果开发者在errorHandler函数中手动抛出同样错误信息throw err
# 判断err信息是否相等,避免log两次
# 如果抛出新的错误信息throw err Error('你好毒'),将会一起log输出
if (e !== err) {
logError(e, null, 'config.errorHandler')
}
}
}
# 未配置常规log输出
logError(err, vm, info)
}
# 错误输出函数
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
}
}
Счастливый час
Вышеизложенное является моим простым пониманием обработки ошибок vue.Вы можете комментировать и обмениваться мнениями, вместе добиваться прогресса и наслаждаться!
Справочная документация:
vue ошибка API
vue обработка ошибок
Анализ исходного кода промисов
vue/issues/7074