页面崩溃监控
页面崩溃是最糟糕的用户体验之一。用户看到白屏或页面卡死,你却完全不知道发生了什么。因为崩溃的瞬间,JS 执行环境已经挂了,常规的 try-catch 和错误上报全都不起作用。
所以崩溃监控的核心思路是:在崩溃发生前持续"留痕",崩溃恢复后检查这些痕迹来还原现场。
我用过三种手段,覆盖不同的崩溃场景:
下面逐个看实现。
心跳检测
心跳检测的思路很朴素:页面正常运行时,每隔几秒往 localStorage 写一个时间戳。如果页面崩溃了,这个时间戳就会"停"在崩溃前的那一刻。下次用户打开页面时,检查上次心跳的时间差,超过阈值就说明上次崩了。
页面加载时,检查上次心跳是否"断"了:
局限性:心跳检测只能知道"页面挂了",但不知道为什么挂的。它适合做兜底方案,配合其他手段一起用。
全局错误监听
心跳检测是"事后推断",全局错误监听则是"实时捕获"。两种事件需要分别处理:
资源加载失败(图片、脚本、样式表加载异常)也需要监控,但处理方式不同。资源错误没有 stack,有用的信息是资源地址和失败原因(404、DNS 解析失败、网络断开、CORS 拦截等都可能触发):
上报时附带环境信息,方便排查:
局限性:全局错误监听能捕获大部分 JS 错误,但有两种情况抓不到:
- React 组件渲染错误 — 会被 React 内部吞掉,需要错误边界
- 崩溃前的最后几秒 — 错误可能来不及上报页面就挂了,所以心跳检测仍然是必要的兜底
React 错误边界
React 的渲染错误不会触发 window.error,因为 React 内部已经 catch 了。错误边界(Error Boundary)是 React 提供的官方方案,专门捕获组件树中的渲染异常。
使用时包裹在可能出错的组件外面:
一个常见误区:错误边界不是万能的。它只捕获以下场景:
- 子组件渲染过程中的错误
- 生命周期方法中的错误
- 构造函数中的错误
以下场景它抓不到:
- 事件处理函数中的错误(用 try-catch)
- 异步代码(setTimeout、Promise)
- 服务端渲染
- 错误边界组件自身的错误
三者怎么配合
实际项目中,这三种手段是互补的:
心跳检测是兜底,全局错误监听覆盖大多数 JS 错误,React 错误边界补上 React 专属的盲区。三者一起用,才能尽量减少"页面崩了你却不知道"的情况。