本文展示一个完整的 Vue 3 全局错误处理模块,用于捕获和处理应用中的各种错误。让我详细解释每个部分并提供实际示例。
一、模块结构解析
1.1 模块导览
text
// 文件结构
utils/sys/error-handle.ts
├── vueErrorHandler() // Vue 组件错误处理
├── scriptErrorHandler() // JavaScript 全局错误处理
├── registerPromiseErrorHandler() // Promise 错误处理
├── registerResourceErrorHandler() // 资源加载错误处理
└── setupErrorHandle() // 安装所有错误处理器
二、各功能详解与示例
2.1 Vue 运行时错误处理 (vueErrorHandler)
作用:捕获 Vue 组件中的错误,包括:
- 组件渲染错误
- 生命周期钩子错误
- 事件处理器错误
- 计算属性错误
html
<!-- 示例:故意制造错误的组件 -->
<template>
<div>
<!-- 1. 渲染错误 -->
<div>{{ undefinedVariable }}</div> <!-- 访问未定义的变量 -->
<!-- 2. 方法调用错误 -->
<button @click="throwError">点击抛出错误</button>
<!-- 3. 计算属性错误 -->
<p>{{ computedError }}</p>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
// 4. 生命周期错误
onMounted(() => {
// 故意抛出错误
throw new Error('生命周期钩子错误!')
})
const throwError = () => {
// 5. 事件处理器错误
throw new Error('按钮点击错误!')
}
const computedError = computed(() => {
// 6. 计算属性错误
const obj = null
return obj.someProperty // TypeError: Cannot read property...
})
</script>
错误捕获流程:
- Vue 组件发生错误
vueErrorHandler(err, instance, info)被调用err:错误对象instance:触发错误的 Vue 组件实例info:错误发生的位置信息(如 "render function")
2.2 全局脚本错误处理 (scriptErrorHandler)
作用:捕获 JavaScript 运行时错误和语法错误
js
// 示例 1:同步错误
function causeSyncError() {
// 访问不存在的属性
const obj = null
console.log(obj.property) // TypeError: Cannot read property...
// 调用不存在的函数
undefinedFunction() // ReferenceError: undefinedFunction is not defined
// 语法错误(在开发阶段就会报错)
// console.log('hello' // 缺少右括号
}
// 示例 2:异步错误
setTimeout(() => {
throw new Error('setTimeout 中的错误')
}, 1000)
// 示例 3:跨域脚本错误(只能获取部分信息)
// <script src="https://other-domain.com/error.js"></script>
// 如果 other-domain.com 的脚本出错,只能获得 "Script error."
参数说明:
js
window.onerror = function(
message, // 错误信息
source, // 发生错误的脚本URL
lineno, // 行号
colno, // 列号
error // Error对象
) {
return true // 返回true阻止默认控制台输出
}
2.3 Promise 未捕获错误处理 (registerPromiseErrorHandler)
作用:捕获未处理的 Promise 拒绝(rejection)
js
// 示例 1:未处理的 Promise 拒绝
const brokenPromise = new Promise((resolve, reject) => {
reject(new Error('Promise 被拒绝!'))
})
// 没有 .catch() 处理,错误会被捕获
// 示例 2:异步操作中的错误
async function fetchData() {
const response = await fetch('/api/data')
if (!response.ok) {
throw new Error('API 请求失败')
}
return response.json()
}
// 调用但未处理错误
fetchData() // 错误会被 unhandledrejection 捕获
// 示例 3:链式调用中丢失的错误
Promise.resolve()
.then(() => {
throw new Error('链式调用中的错误')
})
// 如果这里没有 .catch(),错误会被捕获
2.4 资源加载错误处理 (registerResourceErrorHandler)
作用:捕获静态资源加载失败
html
<!-- 示例:资源加载错误 -->
<!DOCTYPE html>
<html>
<body>
<!-- 1. 图片加载失败 -->
<img src="non-existent-image.jpg" alt="不存在的图片">
<!-- 2. CSS 文件加载失败 -->
<link rel="stylesheet" href="non-existent-style.css">
<!-- 3. JavaScript 文件加载失败 -->
<script src="non-existent-script.js"></script>
<!-- 4. 字体文件加载失败 -->
<style>
@font-face {
font-family: 'MyFont';
src: url('non-existent-font.woff2') format('woff2');
}
</style>
</body>
</html>
捕获的事件详情:
js
window.addEventListener('error', (event) => {
const target = event.target
if (target.tagName === 'IMG') {
console.log('图片加载失败:', target.src)
// 可以设置默认图片
target.src = '/default-image.jpg'
}
if (target.tagName === 'SCRIPT') {
console.log('脚本加载失败:', target.src)
// 可以加载备用脚本
}
if (target.tagName === 'LINK' && target.rel === 'stylesheet') {
console.log('样式表加载失败:', target.href)
// 可以加载备用样式
}
}, true) // 使用捕获阶段
三、实际应用示例
3.1 完整配置示例
ts
// main.ts - 使用错误处理
import { createApp } from 'vue'
import App from './App.vue'
import { setupErrorHandle } from './utils/sys/error-handle'
const app = createApp(App)
// 安装错误处理
setupErrorHandle(app)
// 模拟各种错误(用于测试)
if (import.meta.env.DEV) {
// 测试全局错误
window.addEventListener('load', () => {
console.log('错误处理已安装,可以测试以下错误:')
console.log('1. 访问不存在的变量: window.nonExistent')
console.log('2. 抛出错误: throw new Error("测试错误")')
console.log('3. Promise 错误: Promise.reject(new Error("Promise错误"))')
console.log('4. 资源错误: <img src="error.jpg">')
})
}
app.mount('#app')
五、总结
这个错误处理模块提供了四个层次的错误捕获:
- Vue 组件层:捕获组件内部错误
- JavaScript 全局层:捕获所有脚本错误
- Promise 层:捕获未处理的 Promise 拒绝
- 资源加载层:捕获静态资源加载失败
主要价值:
- 提高应用稳定性
- 快速定位和修复问题
- 改善用户体验
- 便于监控和分析