本文目录导读:

我来帮你编写一个全局捕获异步异常信息的脚本,这里提供几种常见场景的实现方案:
浏览器环境 - 全局错误捕获
// global-error-handler.js
class GlobalErrorHandler {
constructor() {
this.init();
}
init() {
// 捕获未处理的Promise异常
window.addEventListener('unhandledrejection', (event) => {
console.error('未处理的Promise拒绝:', {
reason: event.reason,
promise: event.promise,
time: new Date().toISOString()
});
// 记录错误信息
this.logError({
type: 'unhandledrejection',
message: event.reason?.message || String(event.reason),
stack: event.reason?.stack,
timestamp: new Date().toISOString()
});
// 阻止默认处理
event.preventDefault();
});
// 捕获全局错误
window.addEventListener('error', (event) => {
// 过滤资源加载错误
if (event.target && (event.target.tagName || event.target.src)) {
return;
}
console.error('全局错误:', {
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
error: event.error,
time: new Date().toISOString()
});
this.logError({
type: 'global_error',
message: event.message,
stack: event.error?.stack,
filename: event.filename,
line: event.lineno,
column: event.colno,
timestamp: new Date().toISOString()
});
event.preventDefault();
});
// 重写console.error以便控制台错误
const originalConsoleError = console.error;
console.error = (...args) => {
this.logError({
type: 'console_error',
message: args.map(arg => String(arg)).join(' '),
timestamp: new Date().toISOString()
});
originalConsoleError.apply(console, args);
};
}
logError(errorInfo) {
// 这里可以发送到服务器或存储到本地
console.log('错误日志:', errorInfo);
// 示例:发送到服务器
// this.sendToServer(errorInfo);
// 示例:存储到localStorage
// this.saveToLocal(errorInfo);
}
sendToServer(errorInfo) {
fetch('/api/log-error', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(errorInfo)
}).catch(e => console.error('日志发送失败:', e));
}
saveToLocal(errorInfo) {
const errors = JSON.parse(localStorage.getItem('error_logs') || '[]');
errors.push(errorInfo);
// 只保留最近100条
if (errors.length > 100) errors.shift();
localStorage.setItem('error_logs', JSON.stringify(errors));
}
}
// 使用
const errorHandler = new GlobalErrorHandler();
Node.js 环境 - 全局异步错误捕获
// node-global-error-handler.js
class NodeGlobalErrorHandler {
constructor(options = {}) {
this.options = {
exitOnError: false,
logToFile: true,
logPath: './error.log',
...options
};
this.init();
}
init() {
// 捕获未处理的Promise异常
process.on('unhandledRejection', (reason, promise) => {
console.error('未处理的Promise拒绝:', {
reason: reason instanceof Error ? reason.message : reason,
stack: reason instanceof Error ? reason.stack : new Error().stack,
time: new Date().toISOString()
});
this.logError({
type: 'UNHANDLED_REJECTION',
message: reason instanceof Error ? reason.message : String(reason),
stack: reason instanceof Error ? reason.stack : undefined,
timestamp: new Date().toISOString()
});
// 可选择优雅退出
if (this.options.exitOnError) {
process.exit(1);
}
});
// 捕获未捕获的异常
process.on('uncaughtException', (error) => {
console.error('未捕获的异常:', {
message: error.message,
stack: error.stack,
time: new Date().toISOString()
});
this.logError({
type: 'UNCAUGHT_EXCEPTION',
message: error.message,
stack: error.stack,
timestamp: new Date().toISOString()
});
if (this.options.exitOnError) {
process.exit(1);
}
});
// 监听警告
process.on('warning', (warning) => {
console.warn('警告:', warning.message);
this.logError({
type: 'WARNING',
message: warning.message,
stack: warning.stack,
timestamp: new Date().toISOString()
});
});
}
logError(errorInfo) {
const logEntry = JSON.stringify(errorInfo) + '\n';
if (this.options.logToFile) {
const fs = require('fs');
fs.appendFile(this.options.logPath, logEntry, (err) => {
if (err) console.error('写入日志文件失败:', err);
});
}
// 可以添加其他日志存储方式
console.log('错误日志:', errorInfo);
}
}
// 使用
const errorHandler = new NodeGlobalErrorHandler({
exitOnError: false,
logPath: './errors.log'
});
通用异步错误封装
// async-error-wrapper.js
class AsyncErrorWrapper {
// 包装异步函数
static wrapAsync(fn) {
return async (...args) => {
try {
return await fn(...args);
} catch (error) {
this.handleError(error, { functionName: fn.name, args });
throw error; // 重新抛出或返回默认值
}
};
}
// 包装Promise
static wrapPromise(promise, errorHandler = null) {
return promise.catch(error => {
if (errorHandler) {
return errorHandler(error);
}
this.handleError(error);
return null; // 返回默认值
});
}
// 处理错误
static handleError(error, context = {}) {
console.error('异步错误捕获:', {
message: error.message,
stack: error.stack,
time: new Date().toISOString(),
...context
});
// 可以添加自定义错误处理逻辑
// this.sendToServer({ ... });
}
// 重试机制
static async retry(fn, maxRetries = 3, delay = 1000) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
console.warn(`第 ${i + 1} 次重试失败:`, error.message);
if (i === maxRetries - 1) {
throw error;
}
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
}
// 使用示例
const safeAsyncFunction = AsyncErrorWrapper.wrapAsync(async () => {
const response = await fetch('https://api.example.com/data');
return response.json();
});
// 或者包装Promise
const safePromise = AsyncErrorWrapper.wrapPromise(
fetch('https://api.example.com/data'),
(error) => {
console.log('友好的错误处理:', error.message);
return { error: true, message: '请求失败' };
}
);
// 带重试的调用
AsyncErrorWrapper.retry(
async () => fetch('https://api.example.com/data'),
3,
2000
);
完整的生产环境示例
// production-error-handler.js
class ProductionErrorHandler {
constructor(config = {}) {
this.config = {
logLevel: process.env.NODE_ENV === 'production' ? 'error' : 'warn',
sampleRate: 1, // 采样率
maxErrors: 100,
...config
};
this.errorCount = 0;
this.errors = [];
this.init();
}
init() {
this.setupGlobalHandlers();
this.setupFrameworkIntegration();
}
setupGlobalHandlers() {
// 浏览器
if (typeof window !== 'undefined') {
this.setupBrowserHandlers();
}
// Node.js
else {
this.setupNodeHandlers();
}
}
setupBrowserHandlers() {
window.onerror = (message, source, lineno, colno, error) => {
this.captureError('WINDOW_ERROR', {
message,
source,
lineno,
colno,
stack: error?.stack
});
};
window.onunhandledrejection = (event) => {
this.captureError('UNHANDLED_REJECTION', {
message: event.reason?.message || String(event.reason),
stack: event.reason?.stack
});
};
}
setupNodeHandlers() {
process.on('uncaughtException', (error) => {
this.captureError('UNCAUGHT_EXCEPTION', {
message: error.message,
stack: error.stack
});
process.exit(1);
});
process.on('unhandledRejection', (reason) => {
this.captureError('UNHANDLED_REJECTION', {
message: reason instanceof Error ? reason.message : String(reason),
stack: reason instanceof Error ? reason.stack : undefined
});
});
}
captureError(type, data) {
if (this.errorCount >= this.config.maxErrors) return;
if (Math.random() > this.config.sampleRate) return;
const errorEntry = {
type,
timestamp: new Date().toISOString(),
url: typeof window !== 'undefined' ? window.location.href : process.cwd(),
userAgent: navigator?.userAgent,
...data
};
this.errors.push(errorEntry);
this.errorCount++;
this.sendToAnalytics(errorEntry);
this.logToConsole(errorEntry);
}
sendToAnalytics(errorEntry) {
// 发送到错误监控服务
fetch('/api/error-tracking', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(errorEntry)
}).catch(() => {});
}
logToConsole(entry) {
if (this.config.logLevel === 'error') {
console.error('[ErrorHandler]', entry.type, entry.message);
} else {
console.warn('[ErrorHandler]', entry);
}
}
getErrors() {
return this.errors;
}
clearErrors() {
this.errors = [];
this.errorCount = 0;
}
}
// 使用
const errorHandler = new ProductionErrorHandler({
logLevel: 'error',
sampleRate: 0.5,
maxErrors: 1000
});
使用建议
-
不同环境选择不同方案:
- 浏览器端:使用
window.onerror和unhandledrejection - Node.js:使用
process.on事件监听
- 浏览器端:使用
-
错误分级处理:
- 致命错误:立即处理和报警
- 一般错误:记录日志
- 警告信息:只记录不报警
-
性能优化:
- 使用采样率减少性能影响
- 限制错误数量避免内存泄漏
- 异步发送错误日志
-
安全考虑:
- 不要直接暴露错误堆栈给用户
- 敏感信息脱敏处理
- 设置合理的日志级别
-
集成方案:
- 结合 Sentry、TrackJS 等服务
- 自定义日志服务器
- 本地日志文件管理
这些脚本可以根据你的具体需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播