错误处理
Vue 把「渲染期 / 生命周期 / 监听器」里的同步错误自动收集起来,交给你统一处理。和 React 的 Error Boundary 思路类似,但 Vue 用「钩子 + 全局处理器」而非组件。
1. 全局捕获:app.config.errorHandler
应用里任何组件渲染、生命周期、事件处理器抛出的错误,都会冒泡到这:
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
app.config.errorHandler = (err, instance, info) => {
// err: 错误对象;instance: 出错组件实例;info: 出错阶段('render'/'setup'/'watcher' 等)
console.error('[全局错误]', err, info);
reportToSentry(err, info);
};info 很有用:能区分是「渲染时」还是「watcher 回调里」出的错。
2. 组件级捕获:onErrorCaptured
某个祖先组件用 onErrorCaptured 能「截住」后代组件抛出的错误,避免它一路冒泡到全局:
<script setup lang="ts">
import { onErrorCaptured, ref } from 'vue';
const err = ref<Error | null>(null);
onErrorCaptured((e) => {
err.value = e as Error;
return false; // 返回 false 表示「已处理,停止向上传播」
});
</script>
<template>
<div v-if="err" class="banner">出错了:{{ err.message }}</div>
<slot v-else />
</template>onErrorCaptured 回调返回 false 会阻止错误继续向上冒泡(类似 React 里不 rethrow)。返回 true / 不返回则继续向上。
3. 和 React 错误边界对比
| Vue | React | |
|---|---|---|
| 全局捕获 | app.config.errorHandler | window.onerror / 框架无内置全局 handler |
| 局部捕获 | onErrorCaptured 钩子 | componentDidCatch / ErrorBoundary 组件 |
| 阻止冒泡 | 返回 false | 不 rethrow |
| 渲染兜底 UI | 在捕获组件里 v-if 显示错误态 | this.state.hasError 渲染 fallback |
React 必须用「类组件 ErrorBoundary」包一层(函数组件没有 error boundary 能力);Vue 用组合式钩子 onErrorCaptured 即可,任何组件都能当边界。
4. 异步错误 / watch 错误
async 函数里的错误不会被 errorHandler 自动捕获(Promise rejection 走的是微任务,不在 Vue 的同步错误收集范围):
// ❌ 下面的 await 报错不会进 errorHandler
async function load() {
const d = await fetch('/api/x').then((r) => r.json());
}
// ✅ 自己 try/catch 或在调用处接住
async function load() {
try { /* ... */ } catch (e) { app.config.errorHandler?.(e, null, 'async'); }
}watch / watchEffect 的回调里抛错会被捕获并走 errorHandler(Vue 包了回调)。所以「在 watcher 里同步抛错」能进全局处理,但「async 函数里的 rejection」要自己接。
小结
app.config.errorHandler:全局兜底,拿到err / instance / infoonErrorCaptured:祖先组件截住后代错误,返回false阻止冒泡- 比 React:Vue 用钩子即可当边界,无需类组件
- 异步函数里的 rejection 不在 Vue 同步收集范围,要自己 try/catch
写一个 ErrorBoundary.vue:用 onErrorCaptured 捕获后代错误,显示「出错」兜底 UI,并不向上冒泡(自己吞掉)。
在应用入口配置 errorHandler,把错误上报到一个虚构的 reportError 函数,并附上出错阶段 info。
下面代码里 fetch 失败后,为什么不会进全局 errorHandler?怎么修?
async function loadUser() {
const r = await fetch('/api/user');
return r.json(); // 若 /api/user 404,r.json 抛错
}