一、当JavaScript穿上滑板鞋:异步世界的崩塌危机
在Chrome浏览器疯狂输出的现代Web开发中,异步代码就像失控的传送带。让我们想象一个在线支付场景:用户在点击支付按钮后,系统需要依次执行购物车校验、支付渠道选择、银行接口通信三个异步操作。突然银行接口抛出了超时错误,此时若缺乏错误处理机制,这个错误就像落入黑洞的光线,消失在运行时中。
// 技术栈:浏览器环境 + 原生Promise
function processPayment() {
validateCart()
.then(selectPaymentChannel)
.then(connectBankAPI)
.catch(error => { // 最后的安全网
console.error('支付流程爆炸:', error);
trackError(error); // 错误上报
});
}
// 典型错误场景
function connectBankAPI() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('银行接口连接超时'));
}, 5000);
});
}
当这段代码在浏览器默默失败时,产品经理的夺命连环call就会准时响起:"用户说付款没反应!我们的错误监控系统在吃白饭吗?"
二、异步错误的百慕大三角:经典吞噬场景
1. Promise连锁反应
未处理的Promise拒绝就像被踢来踢去的皮球。试看这个订单查询功能:
// 技术栈:Node.js v14+ + ES6
async function queryOrder(userId) {
const db = await connectDatabase(); // 可能断连的数据库
return db.query(`
SELECT * FROM orders
WHERE user_id = ${userId}
`); // 潜在SQL注入?!
}
app.get('/orders', async (req, res) => {
try {
const orders = await queryOrder(req.user.id);
res.json(orders);
} catch (e) {
// 这里的catch无法捕获query中的Promise拒绝
res.status(500).send('服务器抽风');
}
});
当数据库连接断开时,这个错误会直接导致进程崩溃,因为内部的Promise拒绝没有被正确处理。
2. setTimeout暗箭
定时器中的错误就像隐身刺客:
function checkSession() {
setTimeout(() => {
throw new Error('Session已过期'); // 跳脱三界外的错误
}, 300000);
}
// 没有任何try...catch能捕获这个错误
3. 事件监听黑洞
WebSocket连接的异常处理:
// 技术栈:浏览器WebSocket API
const socket = new WebSocket('wss://trade.example.com');
socket.onmessage = async (event) => {
const data = JSON.parse(event.data); // 可能格式错误
await updateTradingView(data); // 可能异步异常
};
// 未被捕获的异常会使整个socket中断
三、构建错误结界:多维防护体系
1. Promise维度的引力场
使用ESLint配置强制要求catch处理:
// .eslintrc配置
{
"rules": {
"promise/catch-or-return": "error"
}
}
// 生产环境代码
fetchOrderDetail(orderId)
.then(renderDetail)
.catch(e => {
showErrorToast('加载详情失败');
reportError(e); // Sentry上报
});
2. async/await的全防护护盾
结合Babel编译的async函数错误追踪:
async function fetchUserAssets() {
try {
const auth = await checkAuthStatus(); // 可能失败
const data = await fetch('/api/assets', {
headers: { Authorization: auth.token }
});
return parseJSON(data); // JSON解析可能出错
} catch (e) {
captureException(e); // Sentry捕捉
throw wrapError(e, '资产加载失败'); // 错误包装
}
}
3. 全局错误结界
浏览器环境的全域监控策略:
// 错误管理中心
class ErrorTracker {
constructor() {
window.addEventListener('error', this.handleRuntimeError);
window.addEventListener('unhandledrejection', this.handlePromiseRejection);
}
handleRuntimeError = (event) => {
this.report({
type: 'RUNTIME_ERROR',
message: event.message,
stack: event.error.stack,
filename: event.filename,
});
return true; // 阻止默认控制台报错
};
handlePromiseRejection = (event) => {
this.report({
type: 'PROMISE_REJECTION',
reason: event.reason,
});
event.preventDefault(); // 阻止控制台警告
};
}
四、错误监控中心建设:从本地到云端
1. 打造前端哨兵系统
搭建简易错误监控服务:
// 基于Express的监控服务
app.post('/log-error', (req, res) => {
const { errorInfo, userAgent, pageURL } = req.body;
// 入库前清洗数据
const cleanedError = sanitizeError(errorInfo);
db.collection('client_errors').insertOne({
...cleanedError,
timestamp: new Date(),
userAgent,
pageURL,
environment: process.env.NODE_ENV,
});
res.sendStatus(200);
});
// 客户端上报封装
function reportToServer(error) {
navigator.sendBeacon('/log-error', {
errorInfo: serializeError(error),
userAgent: navigator.userAgent,
pageURL: location.href,
});
}
2. 接入专业监控平台
以Sentry为例的现代化整合:
// Sentry初始化配置
Sentry.init({
dsn: 'https://your-key@sentry.io/project',
integrations: [
new Sentry.Integrations.GlobalHandlers({
onerror: true,
onunhandledrejection: true,
}),
new Sentry.Integrations.Breadcrumbs({
console: true,
dom: true,
}),
],
beforeSend(event) {
if (event.user) {
delete event.user.email; // 敏感信息过滤
}
return event;
},
});
// React组件错误边界
class ErrorBoundary extends React.Component {
componentDidCatch(error, info) {
Sentry.withScope(scope => {
scope.setExtras(info);
Sentry.captureException(error);
});
}
}
五、实战:电商系统错误处理全流程
// 订单支付完整流程(技术栈:Node.js + Express + Axios)
app.post('/checkout', async (req, res) => {
try {
const paymentData = await validatePayment(req.body);
const paymentResult = await processPayment(paymentData);
await sendPaymentEmail(paymentResult);
res.json({ success: true });
} catch (error) {
// 错误分类处理
if (error instanceof PaymentGatewayError) {
Sentry.addBreadcrumb({
message: '支付网关错误',
data: error.metadata,
});
res.status(503).json({ error: '支付通道拥堵' });
} else if (error instanceof DatabaseError) {
triggerDBAlet(error); // 触发运维告警
res.status(500).json({ error: '系统维护中' });
} else {
res.status(400).json({ error: '请求参数异常' });
}
// 统一上报
Sentry.captureException(error, {
tags: { endpoint: '/checkout' },
});
}
});
// Axios请求拦截器
axios.interceptors.response.use(null, error => {
if (!error.config) return Promise.reject(error);
Sentry.addBreadcrumb({
type: 'http',
data: {
url: error.config.url,
method: error.config.method,
status: error.response?.status,
},
});
return Promise.reject(error);
});
六、监控体系的五角评估模型
1. 覆盖完备性
确保监控范围涵盖:
- 运行时错误
- 异步异常
- 资源加载失败
- API请求错误
- 自定义业务异常
2. 信息完整性
每条错误记录应包含:
- 错误堆栈(SourceMap解析)
- 用户上下文(ID、操作路径)
- 环境信息(浏览器、OS、分辨率)
- 网络状态(在线/离线、网速)
- 业务数据(购物车金额、操作步骤)
七、安全守则:错误处理的十二道金牌
- 生产环境禁用console.error
- 敏感信息过滤(身份证、银行卡号)
- 错误日志访问权限控制
- SourceMap文件隔离存储
- 错误采样率控制(避免DDoS)
- 监控系统熔断机制
- 错误自动分类算法
- 重复错误合并策略
- 实时报警阈值设定
- 错误生命周期管理
- GDPR日志保留策略
- 定期演练监控系统失效场景