背景
在 Web 监控场景中,除了常见的如 FP、FCP、LCP 等都属于页面加载时的性能指标,而页面运行时同样存在一些性能问题导致不好的用户体验,比如丢帧卡顿、内存泄露页面崩溃等。为了能及时发现、定位到这些问题,因此探索运行时的性能监控方案。
本人通常每周都会写文章,但直接粘贴搬运到这里总有很多错乱,逐一检查调整很是繁琐,若文章对你有所帮助,劳烦点赞关注支持一下,我也有动力更新更多内容。若内容存在谬误,请帮忙指正。
下一篇准备更新《使用 Chrome DevTools Performance 进行长任务归因的详细步骤》
性能指标
通常公司内部都有大数据平台,并提供自定义上报和预警功能完成数据收集、分析和预警工作。我们要做的就是确定该收集上报哪些数据,因此下面是对一些常见的运行时性能指标的逐一分析。
FPS
这里的FPS(Frames Per Second)指网页的每秒渲染次数。当 FPS = 60 时表示页面每秒刷新60次,即每 16.7ms 渲染一次,此时用户感知到的页面渲染是流畅的。当 FPS 低于此数值,页面开始丢帧,FPS 越低用户感受到卡顿越明显。
收集与上报
可借助 PerformanceFrameTimg API 获取到当前页面的每帧渲染时间,从而可以计算出 FPS,但由于 PerformanceFrameTiming
存在非常严重的兼容性问题,因此最好的办法是使用requestAnimationFrame()
方法来计算 FPS。其回调方法会在页面下一次重绘前被执行,因此通过计算每秒内 requestAnimationFrame()
的执行次数可计算出页面帧数,并暂时收集起来:
var lastTime = performance.now(); // 上一个1s周期的时间戳
var frame = 0; // 记录帧数
var lastFameTime = performance.now(); // 上一帧发生的时间戳
var loop = function(time) {var now =performance.now();var fs = now - lastFameTime;lastFameTime = now;var fps = Math.round(1000 / fs); // 当前帧的 fps 理论值 = 1s / 相邻两帧的时间间隔frame++;// 如果当前帧在下一个1s周期内if (now > 1000 + lastTime) {var fs = (now - lastTime) / frame; // 一个周期内每帧的平均时间var fps = Math.round(1000 / fs);frame = 0;lastTime = now;};console.log('fps', fps);window.requestAnimationFrame(loop);
}
loop();
这样一来每次都会获得一组 FPS 值👇🏻,每秒可以做一次数据聚合分析:
[57,56,55,23,60,59,46,56,57,54,44,59,31,58,56,42,52,51,54,...]
理论上来说每次 FPS 小于 60 就是一次丢帧,但实际会很多因素造成 FPS 波动,并且略低于 60 并不会导致明显卡顿。因此可以将「连续 n 次的 FPS 低于某阈值 m」才定义为一次卡顿,比如连续3次 FPS 低于20认为是一次卡顿,并进行上报。
function isBlocking(fpsList, below = 20, last = 3) {var count = 0;for (var i = 0; i < fpsList.length; i++) {if (fpsList[i] && fpsList[i] < below) {count++;} else {count = 0;}if (count >= last) {return true;}}return false;
}
推荐方案
1.持续每隔 1s 记录一次页