前端监控解决什么
后端出了问题可以通过日志和指标定位,前端的问题却常常「只在用户那里发生」:某个机型白屏、某个页面按钮点了没反应、某个版本一上线报错率飙升。没有监控,这些全靠用户反馈,又慢又零散。
前端监控要做三件事:把错误接住、把现场还原、把信号变成告警。错误接住靠全局捕获,现场还原靠上报环境信息和用户操作路径,告警让团队在用户抱怨之前就发现问题。
一套完整体系包括错误监控、性能监控和行为埋点三层。三者的数据可以打通:同一个用户会话里,性能差、报错多、流失快,这些信号放一起看,才能定位真正的体验瓶颈。
没有监控的线上前端,等于在盲飞。
- 全局捕获onerror 与 unhandledrejection。
- sourcemap还原压缩代码堆栈。
- 埋点性能与行为数据采集。
- 上报通道、采样与降噪。
错误捕获:onerror 与 unhandledrejection
脚本运行时错误统一走 window.onerror,Promise 失败且没有 catch 时走 unhandledrejection。把这两个入口接住,大部分运行时错误就都有了兜底。
window.addEventListener('error', (e) => {
monitor.report({
type: 'js',
message: e.message,
file: e.filename,
line: e.lineno,
col: e.colno,
stack: e.error ? e.error.stack : ''
});
});
window.addEventListener('unhandledrejection', (e) => {
monitor.report({ type: 'promise', reason: String(e.reason) });
});
注意 error 事件里的资源加载失败(图片、脚本、样式 404)也走这个入口,但它们的 e.target 是元素而不是 Error 对象,要单独区分类型,避免误报。
捕获之后还要能关:某些业务代码确实预期会抛错,可以用标志位或命名约定跳过,否则告警会被噪音淹没,慢慢就没人看了。
资源与网络请求监控
页面白屏最常见的原因是资源加载失败,尤其是 CSS 和脚本。资源监控监听 error 事件里 target 是 HTMLElement 的情况,记录 src 和标签类型。
window.addEventListener('error', (e) => {
const el = e.target;
if (el instanceof HTMLElement) {
monitor.report({ type: 'resource', tag: el.tagName, src: el.src });
}
}, true);
接口请求监控一般拦截 fetch 和 XHR:记录 url、方法、耗时、状态码和响应大小。成功率、平均耗时、P95 这些聚合指标,直接反映后端对前端的服务质量。
请求监控的代码要在业务脚本之前注入,才能覆盖所有请求。这也是为什么成熟的 SDK 都以最早加载的脚本形式引入。
sourcemap 错误还原
生产环境的 JS 都经过压缩混淆,报错堆栈只有一行压缩后的代码,基本没法定位。sourcemap 记录了压缩代码到源码的映射,用它能把行列号翻译回原始文件和函数。
做法是在构建产物里保留 .map 文件,但不直接暴露给浏览器下载,而是上传到监控平台。监控平台收到带行列号的错误后,用 sourcemap 离线还原出源码位置。
// webpack 配置
module.exports = {
devtool: 'hidden-source-map',
// hidden 表示 map 文件存在但不生成注释引用
};
还原的关键是版本对齐:sourcemap 必须和线上 JS 是同一次构建的产物,发布时要把版本号一起上报,否则还原出来的位置是错的。
性能与体验埋点
性能数据用 Performance API 获取:Navigation Timing 提供页面加载各阶段耗时,Resource Timing 提供每个资源耗时,Long Tasks 记录阻塞主线程的长任务。
window.addEventListener('load', () => {
const nav = performance.getEntriesByType('navigation')[0];
monitor.report({
type: 'perf',
ttfb: nav.responseStart - nav.requestStart,
domContentLoaded: nav.domContentLoadedEventEnd - nav.requestStart,
load: nav.loadEventEnd - nav.requestStart,
});
});
体验指标 LCP(最大内容绘制)和 INP(交互响应)是用户感知的核心,可以用 PerformanceObserver 订阅。行为埋点则记录关键动作:点击、滚动、路由切换,把用户路径串起来,出问题时能回放现场。
埋点要克制,只埋能指导决策的事件。埋得过多既耗性能,也让分析无从下手。
上报通道与采样降噪
上报要走独立于业务接口的通道,避免业务接口故障时上报也跟着失败。最常见的是 navigator.sendBeacon,页面关闭时也能把数据发出去,适合埋点和错误上报。
navigator.sendBeacon('/api/collect', JSON.stringify(payload));
量大时要做采样和聚合:错误按「错误信息 + 位置 + 版本」去重聚合,前端只上报聚合后的计数,或者按比例随机采样。同一错误在同一个浏览器里只上报一次,用 localStorage 做去重。
隐私合规也要考虑:上报内容避免包含用户明文敏感信息,需要的话做脱敏。灰度阶段可以先只收集不上报告警,验证链路稳定后再全量开启。
监控体系落地清单
- 全局接住 error 与 unhandledrejection,区分脚本与资源错误。
- 拦截 fetch/XHR 统计接口成功率与耗时。
- 构建保留 hidden-source-map,上传平台离线还原。
- 采集 LCP、INP 等体验指标,按版本聚合对比。
- 用 sendBeacon 独立上报,采样去重控制量级。
- 发布新版本时带上版本号,灰度观察后再放量。
监控的价值,是让问题发生在用户之前发现之前。