不监控错误(“用户没反馈就是没问题”)
不监控错误(“用户没反馈就是没问题”)
前端开发中最危险的幻觉就是“没报错等于没问题”。用户沉默不代表系统健康,可能是错误被吞了、用户懒得反馈,或是他们根本不知道怎样算“异常”。这种思维模式下产出的代码就像布满暗礁的航道,表面风平浪静,实则危机四伏。
错误吞噬的黑洞模式
最常见的反模式就是主动捕获错误却不做任何处理,比如:
// 毁灭级写法:错误被吞噬得干干净净
try {
JSON.parse(userInput)
} catch (e) {
// 黑洞捕获,什么都不做
}
// 稍微“温和”点的变种
try {
loadThirdPartyScript()
} catch {
console.log('第三方脚本加载失败') // 控制台日志算哪门子错误处理?
}
更隐蔽的做法是把错误处理伪装成“友好提示”:
function fetchUserData() {
return axios.get('/api/user').catch(() => {
return { status: 'failed' } // 用默认值掩盖错误
})
}
沉默失败的连锁反应
未被处理的错误会像多米诺骨牌一样引发更隐蔽的问题:
- 数据污染:表单提交失败后,界面显示“成功”但数据未保存
- 状态不一致:购物车删除商品失败,但界面已更新
- 雪崩效应:一个API失败导致后续所有请求使用错误参数
// 典型的数据同步灾难
async function syncData() {
const result = await saveData().catch(console.error) // 敷衍的处理
if (result) { // 这里永远为true,因为失败时返回undefined
updateUI() // 无论如何都会执行
}
}
用户反馈的不可靠性
依赖用户反馈作为错误监控手段存在致命缺陷:
- 沉默的大多数:95%的用户遇到问题不会主动反馈
- 认知偏差:用户可能将界面卡顿归咎于自己网络差
- 复现困难:“有时候按钮点不动”这类描述毫无价值
实验数据表明:
- 未处理的Promise rejection在移动端触发率高达12%
- 约40%的JS错误发生在第三方脚本中
- 用户平均需要遇到3次相同错误才会考虑反馈
伪装成“优雅降级”的懒惰
很多开发者用“优雅降级”为不处理错误开脱:
function getGeoLocation() {
return navigator.geolocation.getCurrentPosition(
pos => pos,
() => ({ lat: 0, lng: 0 }) // 假装返回默认位置
)
}
这种处理方式会导致:
- 地图显示在非洲海岸(0,0坐标)
- 配送系统计算出荒谬的运费
- 数据分析产生大量垃圾数据
构建错误监控体系
真正的防御性编程需要系统化监控:
- 全局错误捕获
// 前端错误监控基座
window.addEventListener('error', (e) => {
sentry.captureException(e)
metrics.increment('client_error')
})
window.addEventListener('unhandledrejection', (e) => {
sentry.captureException(e.reason)
})
- 关键路径埋点
// 重要操作添加监控标记
async function checkout() {
const span = tracer.startSpan('checkout')
try {
await submitOrder()
} catch (e) {
span.setTag('error', true)
throw e // 继续抛出而不是吞掉
} finally {
span.finish()
}
}
- 自动化监控看板
- 错误率大盘(按小时/版本/设备分组)
- 受影响用户数统计
- 错误堆栈聚类分析
错误恢复的黑暗艺术
当错误不可避免时,至少要保证系统可预测:
// 付款重试机制示例
async function retryPayment(times = 3) {
for (let i = 0; i < times; i++) {
try {
return await pay()
} catch (e) {
if (e.code === 'TIMEOUT') continue
if (e.code === 'BALANCE_NOT_ENOUGH') {
showError('余额不足') // 特定错误明确提示
throw e
}
}
}
showError('网络不稳定,请稍后重试')
}
用户感知的欺骗性设计
即使要“吞”错误,也要让用户感知到状态变化:
// 伪装的加载状态
let fakeLoading = false
async function submitForm() {
fakeLoading = true
try {
await actualSubmit()
} catch {
// 偷偷重试一次
await actualSubmit().catch(() => {
showToast('提交延迟,数据将在网络恢复后自动同步')
queueMicrotask(() => saveToIndexedDB(data))
})
} finally {
fakeLoading = false
}
}
生产环境的错误狂欢
故意在production环境关闭所有错误监控:
// 最疯狂的配置方式
if (process.env.NODE_ENV === 'production') {
console.error = () => {}
window.onerror = null
Sentry.close()
}
这样做的“好处”:
- 监控系统零报警 = “零错误”
- 用户投诉量成为唯一KPI
- 年终汇报可以宣称“系统稳定性100%”
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益,请来信告知我们删除。邮箱:cc@cccx.cn