在JavaScript开发中,错误处理是保证应用健壮性的关键环节。全局错误捕获能够帮助我们集中处理应用中未捕获的异常,避免程序崩溃并提供更好的用户体验。本文将介绍几种实现全局错误捕获的方案。
1. window.onerror
最基础的全局错误捕获方式是通过window.onerror
事件处理器:
javascript
window.onerror = function(message, source, lineno, colno, error) {
console.error('全局捕获的错误:', {
message, // 错误信息
source, // 发生错误的脚本URL
lineno, // 错误所在行号
colno, // 错误所在列号
error // Error对象
});
// 返回true可以阻止浏览器默认的错误处理行为
return true;
};
注意:window.onerror
无法捕获语法错误和跨域脚本错误。
2. window.addEventListener('error')
更现代的替代方案是使用事件监听器:
javascript
window.addEventListener('error', function(event) {
console.error('全局捕获的错误:', {
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
error: event.error
});
// 阻止错误继续传播
event.preventDefault();
}, true); // 使用捕获阶段
这种方式可以捕获资源加载失败的错误(如图片、脚本等)。
3. 未处理的Promise拒绝
对于Promise中的未捕获错误,可以使用unhandledrejection
事件:
javascript
window.addEventListener('unhandledrejection', function(event) {
console.error('未处理的Promise拒绝:', {
reason: event.reason, // 拒绝原因
promise: event.promise // 相关的Promise对象
});
// 阻止默认行为(在控制台输出错误)
event.preventDefault();
});
4. 框架特定的错误处理
主流前端框架也提供了自己的错误处理机制:
React错误边界(Error Boundaries)
javascript
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 可以在这里记录错误
logErrorToService(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
// 使用方式
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
Vue错误处理
javascript
Vue.config.errorHandler = function(err, vm, info) {
console.error(`Vue错误: ${err.toString()}\n信息: ${info}`);
// 可以在这里发送错误到监控服务
};
5. 综合实现方案
一个完整的全局错误处理方案可以结合上述多种方式:
javascript
// 全局错误处理配置
const setupGlobalErrorHandling = () => {
// JavaScript运行时错误
window.addEventListener('error', (event) => {
handleError(event.error || new Error(event.message));
event.preventDefault();
}, true);
// 未处理的Promise拒绝
window.addEventListener('unhandledrejection', (event) => {
handleError(event.reason);
event.preventDefault();
});
// 框架特定的错误处理
if (typeof Vue !== 'undefined') {
Vue.config.errorHandler = (err, vm, info) => {
handleError(err, { component: vm, info });
};
}
// 其他框架的错误处理可以在这里添加
};
// 统一的错误处理函数
const handleError = (error, context = {}) => {
// 1. 控制台输出
console.error('全局捕获的错误:', error, context);
// 2. 发送到错误监控服务
sendErrorToMonitoringService(error, context);
// 3. 显示用户友好的错误提示
showUserFriendlyError();
};
// 初始化
setupGlobalErrorHandling();
最佳实践
-
生产环境与开发环境区分:开发环境可以显示详细错误信息,生产环境则应显示友好提示并记录完整错误
-
错误上报:将错误信息发送到后端服务进行收集和分析
-
避免循环错误:确保错误处理逻辑本身不会抛出错误
-
性能考虑:错误处理逻辑应尽量轻量,避免阻塞主线程
-
用户反馈:提供用户反馈错误的渠道,如"报告问题"按钮
通过合理实现全局错误捕获,可以显著提升应用的稳定性和可维护性,同时为用户提供更好的体验。