Vue.js: 错误处理与调试
最后更新:2026-10-20
错误处理是任何生产级应用的必备能力——应用崩了能快速定位、优雅降级、通知用户。Vue 3 提供了多层次错误处理:errorHandler(全局)、onErrorCaptured(局部)、errorCaptured 钩子(组件级)。
调试和性能优化同样重要——Vue DevTools 是必备工具,能让你看清组件树、状态、事件、性能瓶颈。
1. 你将学到
- 3 层错误处理:errorHandler / onErrorCaptured / errorBoundary
- Vue DevTools 4 大核心功能(组件树 / 状态 / 事件 / 性能)
- 性能分析(performance API + DevTools)
- Sentry 集成(生产环境错误监控)
- Source Map 错误定位
- 5 大常见调试技巧
2. 一个白屏崩溃"找不到原因"事件
(1) 痛点:1 个 API 报错,整个页面空白
Alice 的后台出了 1 个严重 Bug:
JS
// ProductList.vue
const products = ref([])
onMounted(async () => {
const res = await fetch('/api/products')
products.value = await res.json() // ❌ 后端返回非 JSON → 报错
})
用户体验:
- 整个 ProductList 页面白屏
- 错误信息只在 console
- 用户看到空白页,刷新也没用
产品经理 Charlie:
"Alice,客户抱怨页面白屏。我们需要:1)不让整个页面崩溃,2)显示错误信息,3)上报到监控系统。"
(2) Vue 错误边界解法
用户体验:
- 错误被捕获,不传播
- 显示友好错误页面
- 错误自动上报 Sentry
- 用户可点击"重试"
(3) 收益
加上错误处理后:
- 白屏崩溃:100% → 0
- 错误定位:console → Sentry 仪表盘
- 用户体验:崩溃 → 友好提示
- 可观测性:所有错误有据可查
3. 3 层错误处理
(1) 全局错误处理:app.config.errorHandler
JS
// main.js
const { createApp } = Vue
import App from './App.vue'
const app = createApp(App)
// ✅ 全局错误处理
app.config.errorHandler = (err, instance, info) => {
console.error('Global error:', err)
console.log('Component:', instance)
console.log('Info:', info) // 'render' / 'watch' / 'lifecycle hook'
// 上报到 Sentry
Sentry.captureException(err)
// 用户通知
showErrorNotification('Something went wrong')
}
(2) 组件级错误:onErrorCaptured
(3) 错误层级对比
| 层级 | API | 捕获范围 | 适用 |
|---|---|---|---|
| 全局 | app.config.errorHandler |
所有未捕获错误 | 生产环境必须 |
| 组件 | onErrorCaptured |
子组件错误 | 局部错误边界 |
| 异步 | try/catch / window.onunhandledrejection | Promise 错误 | 手动处理 |
(4) 5 大错误来源
JS
// 1. 渲染错误(模板语法错)
app.config.errorHandler = (err, instance, info) => {
if (info === 'render') console.error('Render error:', err)
}
// 2. 生命周期钩子错误
if (info === 'mounted') console.error('Mounted error:', err)
// 3. watch 回调错误
if (info === 'watcher callback') console.error('Watch error:', err)
// 4. 自定义指令错误
if (info === 'directive') console.error('Directive error:', err)
// 5. 事件处理错误
if (info === 'v-on handler') console.error('Event error:', err)
▶ 示例:Vue 3 全局错误处理(⚠️ 需 Vite 项目 main.js)
JS
// main.js
app.config.errorHandler = (err, instance, info) => {
console.error('[Global]', err, info)
// 上报到 Sentry / 自己的日志服务
// Sentry.captureException(err)
}
输出:
TEXT
页面本身无变化;组件渲染或生命周期抛错时,控制台输出「[Global] 错误对象 render」等日志。
该 handler 会收到 err、组件实例和 info 字段,可在这里接入 Sentry 等日志服务上报。
4. Vue DevTools 调试
(1) 4 大核心面板
| 面板 | 功能 | 用途 |
|---|---|---|
| Components | 组件树、状态、props、emits | 看清组件结构、调试数据 |
| Timeline | 事件、生命周期、性能 | 追踪事件流、性能瓶颈 |
| Pinia/Vuex | Store 状态 | 调试全局状态 |
| Routes | 路由历史 | 调试路由跳转 |
(2) Components 面板使用
TEXT
1. 打开 DevTools(F12 / Cmd+Opt+I)
2. 切换到 Vue 标签
3. 点击组件树中的组件
4. 右侧显示:
- State(响应式数据)
- Props
- Emits
- Slots
- Lifecycle
(3) 5 大 DevTools 技巧
JS
// 1. 实时修改 state(开发模式)
// DevTools 中直接编辑,看组件实时响应
// 2. 时间旅行(Pinia)
// 切换到 Pinia 面板 → Base → 可以回放每一步 state 变化
// 3. 性能标记
// import { markRaw } from 'vue'
// 大数据对象用 markRaw 标记,DevTools 不会深遍历
// 4. 组件 highlight
// DevTools → 右上角"眼睛"图标 → 鼠标悬停高亮组件
// 5. 路由跳转
// DevTools → Routing 标签 → 看每次跳转的 path + params
(4) 安装 Vue DevTools
BASH
# Chrome 扩展
# https://chromewebstore.google.com/detail/vuejs-devtools/odjccnclnlddjlajjphfdmhnlhaglgki
# Firefox 扩展
# https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/
# 或独立应用(推荐)
# https://devtools.vuejs.org/
5. 性能分析
(1) Vue 3 性能 API
JS
const { onMounted, onUnmounted } = Vue
onMounted(() => {
performance.mark('app-start')
// 你的代码
loadData()
performance.mark('app-end')
performance.measure('app-load', 'app-start', 'app-end')
const measure = performance.getEntriesByName('app-load')[0]
console.log(`App loaded in ${measure.duration}ms`)
})
(2) 5 大性能优化技巧
JS
// 1. v-once:只渲染一次
<h1 v-once>{{ title }}</h1>
// 2. v-memo:缓存子树
<div v-memo="[item.id, item.updatedAt]">
<!-- 只在 id 或 updatedAt 变化时重渲染 -->
</div>
// 3. shallowRef:大数据不深响应
const bigList = shallowRef([...10000 items])
// 4. markRaw:第三方库不响应
const map = markRaw(new Map())
// 5. 懒加载:路由 / 组件
const Heavy = defineAsyncComponent(() => import('./Heavy.vue'))
(3) 5 大性能指标
| 指标 | 目标 | 测量方法 |
|---|---|---|
| FCP(首次内容渲染) | < 1.8s | Lighthouse |
| LCP(最大内容渲染) | < 2.5s | Lighthouse |
| TTI(可交互时间) | < 3.8s | Lighthouse |
| TBT(总阻塞时间) | < 200ms | Lighthouse |
| CLS(布局偏移) | < 0.1 | Lighthouse |
▶ 示例:5 大性能优化(速查)
JS
// 1. v-once(只渲染一次)
<h1 v-once>{{ title }}</h1>
// 2. v-memo(缓存)
<div v-memo="[item.id]">...</div>
// 3. shallowRef(浅响应)
const list = shallowRef([...])
// 4. markRaw(不响应)
const map = markRaw(new Map())
// 5. 异步组件(懒加载)
const Heavy = defineAsyncComponent(() => import('./Heavy.vue'))
输出:
TEXT
页面外观与未优化时一致,只是更新行为改变:v-once 内容不再随数据变化,v-memo 依赖不变时跳过更新。
shallowRef 只跟踪 .value 替换,markRaw 对象不会被转为响应式,异步组件首次渲染时按需加载。
6. Sentry 集成
(1) 安装
BASH
npm install @sentry/vue @sentry/tracing
(2) main.js 配置
JS
const { createApp } = Vue
import * as Sentry from '@sentry/vue'
import { Integrations } from '@sentry/tracing'
import App from './App.vue'
const app = createApp(App)
// 1. 初始化 Sentry(app 必须先创建)
Sentry.init({
app,
dsn: 'https://your-dsn@sentry.io/123',
integrations: [
new Integrations.BrowserTracing()
],
tracesSampleRate: 1.0,
// 生产环境降低采样
// tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0
// Vue 特定配置
logErrors: true,
release: '1.0.0',
environment: process.env.NODE_ENV
})
// 2. 全局错误上报
app.config.errorHandler = (err, instance, info) => {
Sentry.captureException(err, {
extra: {
component: instance?.$options.name,
info
}
})
}
(3) Source Map 配置
JS
// vite.config.js
export default {
build: {
sourcemap: true // 生产环境也生成 source map
}
}
// Sentry 上传 source map
// @sentry/cli releases -o your-org -p your-project files upload-sourcemaps ./dist
(4) 5 大 Sentry 功能
| 功能 | 用途 |
|---|---|
| 错误监控 | 自动捕获所有错误,仪表盘查看 |
| 性能追踪 | 慢请求、Slow DB 查询定位 |
| 会话回放 | 用户操作录屏,看错误现场 |
| 发布健康 | 每次发版错误率对比 |
| 告警 | Slack / Email 通知 |
7. 综合演练:错误边界兜底实战
▶ 示例:3 层错误处理(CDN 可演示 ErrorBoundary)
▶ 试一试输出:
TEXT
初始显示「触发子组件错误」按钮,以及两段正常文字:「ErrorBoundary 之外的组件 - 正常工作」和「ErrorBoundary 内的子组件 - 正常」。
点击按钮后,第二个边界内出现红色「⚠️ Error caught: Cannot read properties of null (reading 'foo')」和「重试」按钮,第一个边界外的文字仍正常显示。
点「重试」清除错误并重新渲染子组件,按钮文字变回「触发子组件错误」。
(1) 📊 5 大错误来源(info 字段)
| info 字段 | 含义 | 例子 |
|---|---|---|
'render' |
渲染错误 | 模板引用未定义变量 |
'mounted' / 'updated' |
生命周期错误 | onMounted 中访问 DOM 失败 |
'watcher callback' |
watch 错误 | watch 回调异常 |
'directive' |
指令错误 | 自定义指令 mounted 异常 |
'v-on handler' |
事件错误 | @click 处理函数 throw |
(2) 📊 5 个常见错误速查
| 错误 | 现象 | 解决 |
|---|---|---|
| 白屏崩溃 | 1 个组件错全挂 | 用 ErrorBoundary 包裹 |
| 错误吞掉 | 子组件静默失败 | onErrorCaptured 不要忘 return false |
| Source Map 缺失 | 生产错误无法定位 | vite build sourcemap: true |
| 性能差 | 列表 1000 项卡顿 | v-memo + shallowRef |
| 内存泄漏 | 组件销毁后定时器还在 | onUnmounted 清理 |
(3) 📊 5 大调试场景
| 场景 | 工具 |
|---|---|
| 组件状态异常 | Vue DevTools → State |
| 事件不触发 | Vue DevTools → Timeline |
| 路由跳转错 | DevTools → Routing |
| 生产环境崩溃 | Sentry 仪表盘 |
| 性能慢 | Lighthouse + DevTools Performance |
❓ 常见问题
Q errorHandler 能捕获异步错误吗?
A 不能。
errorHandler 只捕获 Vue 内部的同步错误。异步错误(Promise / setTimeout)需要 try/catch 或 window.addEventListener('unhandledrejection')。Q onErrorCaptured 必须 return false 吗?
A 不是必须。return false 阻止错误向上传播。return true(或不 return)让错误继续向上传播到全局 errorHandler。
Q Vue DevTools 在生产环境能用吗?
A 能。生产构建会自动启用 DevTools(不影响性能)。但建议在生产环境用
Vue.config.devtools = false 关闭(避免暴露内部结构)。Q Sentry 怎么收费?
A 免费版每月 5,000 events + 10,000 performance transactions。中型项目够用。超出后按量计费。
Q v-memo 和 v-for 怎么配合?
A
<div v-for="item in items" :key="item.id" v-memo="[item.id, item.updatedAt]">,只有 id 或 updatedAt 变化时才重渲染这个 div。Q 怎么调试 SSR 应用?
A VS Code 调试器 + Node.js inspect 模式。或 Sentry 捕获服务端错误。或在 Nuxt 3 中用 Nitro 调试工具。
Q onErrorCaptured 在 Vue 3 和 Vue 2 区别?
A Vue 2 是
errorCaptured 钩子,Vue 3 是 onErrorCaptured 组合式 API。Vue 3 还新增全局 app.config.errorHandler。📖 小节
- 3 层错误处理:全局(errorHandler)+ 组件(onErrorCaptured)+ 异步(try/catch)
- 5 大错误来源:render / 生命周期 / watch / 指令 / 事件
- Vue DevTools 4 大面板:Components / Timeline / Pinia / Routes
- 5 大性能优化:v-once / v-memo / shallowRef / markRaw / 懒加载
- Sentry 集成:自动捕获 + 性能追踪 + Source Map
- 5 大性能指标:FCP / LCP / TTI / TBT / CLS
- 生产环境必备:ErrorBoundary + Sentry + Source Map
📝 作业
-
基础题(难度⭐) 实现一个 ErrorBoundary 组件:
- onErrorCaptured 捕获子组件错误
- 显示友好的错误页面
- 提供"重试"按钮
-
进阶题(难度⭐⭐) 实现完整的错误处理系统:
- 全局 errorHandler 上报到控制台
- 组件级 ErrorBoundary
- 异步错误 try/catch
- 5 种错误来源分类
-
挑战题(难度⭐⭐⭐) 实现完整的"生产级"调试 + 错误监控:
- ErrorBoundary 组件 + 3 个不同位置
- Sentry 集成(生产环境)
- Source Map 配置
- Vue DevTools 5 大调试技巧
- 5 大性能优化(v-memo / shallowRef / markRaw / 懒加载 / v-once)
- 5 大性能指标监控(Lighthouse 集成)