cydd / static /js /core /error-boundary.js
chaofenghui's picture
Upload folder using huggingface_hub
dd92d97 verified
Raw
History Blame Contribute Delete
3.94 kB
/**
* Error Boundary Module
* 全局错误捕获与处理,防止未处理异常导致页面崩溃
*/
// ========== 全局错误边界 ==========
const ErrorBoundary = {
_toastContainer: null,
init() {
// 捕获未处理的 Promise 拒绝
window.addEventListener('unhandledrejection', (event) => {
console.error('[ErrorBoundary] Unhandled promise rejection:', event.reason);
// 如果是离线错误,不显示 toast
if (event.reason && event.reason.message === 'OFFLINE') {
return;
}
this.showToast('操作失败,请重试', 'error');
event.preventDefault();
});
// 捕获全局 JS 错误
window.addEventListener('error', (event) => {
console.error('[ErrorBoundary] Uncaught error:', event.error || event.message);
// 忽略资源加载错误(由网络问题引起)
if (event.target && event.target !== window) {
return;
}
this.showToast('页面出现错误,请刷新重试', 'error');
});
console.log('[ErrorBoundary] 全局错误边界已初始化');
},
/**
* 显示 Toast 通知
* @param {string} message - 消息内容
* @param {'info'|'success'|'warning'|'error'} type - 消息类型
* @param {number} duration - 显示时长(毫秒)
*/
showToast(message, type = 'info', duration = 3000) {
if (!this._toastContainer) {
this._toastContainer = document.createElement('div');
this._toastContainer.id = 'toast-container';
this._toastContainer.style.cssText = `
position: fixed; top: 20px; right: 20px; z-index: 10000;
display: flex; flex-direction: column; gap: 8px; pointer-events: none;
`;
document.body.appendChild(this._toastContainer);
}
const colors = {
info: 'var(--deep-blue, #1a73e8)',
success: 'var(--success, #34a853)',
warning: 'var(--warning, #fbbc04)',
error: 'var(--danger, #ea4335)'
};
const toast = document.createElement('div');
toast.className = 'toast-notification';
toast.style.cssText = `
background: ${colors[type] || colors.info}; color: white;
padding: 12px 20px; border-radius: 8px; font-size: 14px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15); pointer-events: auto;
opacity: 0; transform: translateX(20px);
transition: opacity 0.3s, transform 0.3s;
max-width: 320px; word-break: break-word;
`;
toast.textContent = message;
this._toastContainer.appendChild(toast);
// Animate in
requestAnimationFrame(() => {
toast.style.opacity = '1';
toast.style.transform = 'translateX(0)';
});
// Auto dismiss
setTimeout(() => {
toast.style.opacity = '0';
toast.style.transform = 'translateX(20px)';
setTimeout(() => toast.remove(), 300);
}, duration);
},
/**
* 安全执行异步函数,捕获错误并显示 toast
* @param {Function} fn - 异步函数
* @param {string} errorMsg - 错误时显示的消息
* @returns {Promise<any>}
*/
async wrap(fn, errorMsg = '操作失败') {
try {
return await fn();
} catch (error) {
console.error('[ErrorBoundary] Wrapped function error:', error);
if (error.message !== 'OFFLINE') {
this.showToast(errorMsg, 'error');
}
return null;
}
}
};
// 暴露为全局
window.ErrorBoundary = ErrorBoundary;
// 自动初始化
document.addEventListener('DOMContentLoaded', () => {
ErrorBoundary.init();
});