前端监控
项目上线后
当一个需求经过开发、体验、测试、上线后,并不简单意味着这个需求的生命周期就结束了。不仅要应付上线后才发现bug,还需要收集一些信息用以改善用户体验和指明产品优化的方向,这就是前端监控。
从技术方面来讲,前端性能监控主要分为两种方式,一种叫做合成监控(Synthetic Monitoring,SYN),另一种是真实用户监控(Real User Monitoring,RUM)。
合成监控就是在一个模拟场景里,去提交一个需要做性能审计的页面,通过一系列的工具、规则去运行你的页面,提取一些性能指标,得出一个审计报告。比如Google devtools里的Lighthouse。
下面主要以RUM展开。
前端监控的分类
前端监控必须在保护用户隐私的前提下进行。大致分为三类:数据监控、性能监控和异常监控。
数据监控
数据监控是为了收集跟用户相关的数据,大致如下:
- 用户设备类型,浏览器版本,webview引擎类型
- PV(Page View,页面浏览量)、UV(User View,用户浏览量)
- 页面停留时间
- 页面点击分布
- 页面跳转来源
这些数据对于产品来说是很重要的,比如统计来源可以知道推广是否有效,用户停留时间久的页面可以考虑在不影响用户体验的情况下投放广告等等。
性能监控
性能监控是面向开发者的,有了这部分数据,才有依据去改善用户体验,大致如下:
- 白屏时间
- 页面资源加载耗时
- 首屏渲染耗时
- 接口请求耗时
- 收集长时间运行任务(longtasks)
页面加载到完整展示的所有阶段如下:
一般使用performance接口去采集数据。
白屏时间,主要是指header解析完,body开始渲染的时刻。
通过 PerformanceResourceTiming 可以收集各个静态资源的下载时间,需要团队确定哪些数据是比较关系的。
首屏渲染耗时,由于现在的很多单页应用都是使用Vue或者React来处理的,所以会导致一种情况,就是以前我们可以通过在body底部添加时间戳来收集首屏渲染耗时,但是使用Vue或者React的情况页面元素会非常简单,都是需要JS构建好虚拟DOM之后才会生成真实DOM,所以老方法并不可靠。好在现在有了一个新的Web API:MutationObserver,它可以监听一个节点的子树的变化,所以我们可以在监听Vue或者React最终挂载的节点上,并收集时间戳。如果首屏需要异步加载一些数据的话,可以添加一些逻辑,等待所有请求结束时才收集Mutation时间戳。
接口请求耗时,这就比较简单了,可以使用装饰者模式修改请求接口,收集开始请求和结束请求的差值。
长时间运行任务( longtasks ),是指运行时间大于50ms的task,可以定时收集这部分数据并上报。
异常监控
异常是非常重要的,直接关系到用户体验。分类大致如下:
- 运行时异常,还可以分为主动捕获异常(try...catch...)和全局异常(window.onerror)
- 资源文件异常,比如js文件、css文件、img图片等加载不到
- promise异常(try...catch,window.onunhandledrejection)
- 网络请求异常,如ajax、fetch
- 页面崩溃
跨域脚本可以通过在标签上添加crossorigin属性,并且要求请求js文件的响应报文加上Access-Control-Allow-Origin
的响应头 (这部分由提供js文件的服务器加上)。
页面崩溃有两种方式,第一种是在下次打开该网页的时候再上报,参考 Logging Information on Browser Crashes ,第二种是借助Service Worker。
上报方式
上报方式主要有两种:
ajax
和
img.src
,其中后一种可以解决跨域问题,但是如果上报的内容太多的话会受限于URL最大长度限制。使用ajax的时候,如果需要在网页关闭那一刻才上报的话(比如用户停留在页面的事件),可以在
window.onunload
事件里使用同步的ajax,也可以使用
navigator.sendBeacon()
接口上报。
navigator.sendBeacon()
用于满足统计和诊断代码的需要,这些代码通常尝试在卸载(unload)文档之前向web服务器发送数据。过早的发送数据可能导致错过收集数据的机会。使用sendBeacon()
方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能。这就解决了提交分析数据时的所有的问题:数据可靠,传输异步并且不会影响下一页面的加载。
如果页面访问量很大,可以设置采集率缓解服务器压力,采集率可以依赖随机数或者用户特征。
还有一种场景需要考虑,就是如果上报是采用异步堆积上报的方式,如果遇到用户关闭页面而导致没有办法上报的情况该怎么办呢?我们可以考虑使用localStorage的方式去处理,先把上报信息存储到本地,如果异步上报成功后,就清理本地存储;如果没有来得及上报的话,下次访问页面可以继续读取本地存储,如果有数据则继续上报。
监控应用
收集到的这些数据,可应用的场景大概有两个:
- 错误告警
- 性能分析
- 产品分析
错误告警,每个团队的标准不一样,可以自定义告警的阈值,比如收集到的错误上报达到多少数量级或者百分比后就触发告警,并抄送邮件给相关人员。
性能分析,这一块也比较重要,主要考核几个点:用户可交互时间点,是否存在longtasks等待,因为数据比较多,主要考虑使用掐头去尾的均值作为评估值。
产品分析,收集到的信息可以还原成一个个用户故事,对于公司战略有很大帮助。这部分一般都会使用一些图表渲染库,开源的就有很多,比如Chart.js。