Vue 应用中错误怎样分层捕获?errorHandler 和 errorCaptured 能捕获什么?
先理解原理和示例,再练习完整口述与追问。
回答要点
app.config.errorHandler 是应用级兜底,能捕获组件渲染、生命周期、侦听器、事件处理函数以及 setup 中返回的 Promise 拒绝;onErrorCaptured 捕获后代组件错误,可实现局部错误边界,返回 false 阻止继续向上传播。不在 Vue 调用链里的异步错误,例如裸 setTimeout,需要 window error 与 unhandledrejection 兜底。
原理拆解
Vue 调用用户代码时会用 callWithErrorHandling 或 callWithAsyncErrorHandling 包裹:同步错误被 try...catch 捕获,返回 Promise 的钩子与事件处理函数会接上 catch。错误沿组件父链向上传给每层的 errorCaptured,最终到达 errorHandler;回调参数包含错误、组件实例和信息字符串(如哪个钩子)。
在 setup 中自行调用 setTimeout(() => { throw err }),或在 fetchData().then() 里抛错却不返回 Promise,Vue 无法感知,只能由全局事件兜底。app.config.warnHandler 只在开发环境处理警告。Vue Router 的 router.onError 捕获导航守卫和懒加载组件失败,可在此处理 chunk 加载失败(见宝典 43)。
示例与推演
<script setup>
import { ref, onErrorCaptured } from 'vue'
const failed = ref(false)
onErrorCaptured((error, instance, info) => {
failed.value = true
report(error, { info })
return false
})
</script>
<template>
<div v-if="failed">模块加载失败 <button @click="failed = false">重试</button></div>
<slot v-else />
</template>
这个组件包裹第三方图表,图表渲染出错时只显示该区域的降级 UI,不影响整个页面。
易错点
errorCaptured 不捕获组件自身的错误,只捕获后代;错误边界组件自身渲染出错仍会上抛。errorHandler 中再抛错会导致死循环风险,要保证上报函数本身安全。
参考回答可直接练习口述
我会分三层:局部用 onErrorCaptured 做错误边界,捕获后代组件渲染、生命周期、事件处理的错误,显示降级 UI 并返回 false 阻止上抛;应用级用 app.config.errorHandler 统一上报,路由懒加载失败用 router.onError;不在 Vue 调用链里的异步错误,比如裸定时器、没返回的 Promise,再由 window 的 error 和 unhandledrejection 兜底。