前端监控和页面卡顿

Posted 恪愚

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端监控和页面卡顿相关的知识,希望对你有一定的参考价值。

上一篇文章结尾提到了一个对图片(图片!不是图像!)至关重要的点:采样、量化和编解码
图像的显示需要GPU和CPU两者配合,CPU主要负责视图的创建,布局的计算和视图的绘制,然后进行图片的解码,将生成的位图交给GPU,GPU进行渲染,并将渲染的结果交到帧缓冲区,待下一个VSync 信号到来的时候视频控制器从帧缓冲区取出数据,经过转换,显示到屏幕上。
如果在规定的16.7ms内,CPU和GPU的合作未完成,没有生成新的渲染数据到帧缓冲区中,那么就会出现卡顿或者掉帧的情况。

一般我们常说的“精灵图”Sprite 其实不止优化了“网络请求”,也利用了这一点,“尽量避免短时间内大量图片的显示,尽可能将多张图片合成一张进行显示”。

除了上面提到的“图片加载”导致的页面卡顿。引起页面卡顿的场景还有很多。大致有两类:

  1. 渲染引起的卡顿
  2. 内存引起的运行卡顿

为了用户体验考虑,我们需要对这些现象进行上报,以便更快、有针对性的进行优化和修复。
其中第一种情况又有:“资源引起的页面掉帧”、“页面 FPS 持续低于预期”、“交互行为引起的渲染问题”。
卡顿严格来说还分为“正常卡顿”和“真实卡顿”(这里“真实”的意思是达到需要上报条件的)。而我们需要上报的就是“真实卡顿”。比如:

  • 在页面 FPS 连续 n 秒内低于一个值时;
  • 当用户进行交互行为后,渲染新的一帧的时间超过 16ms + 100ms时;
  • web worker心跳检测(针对页面崩溃!)

想想看,我们可以把“页面崩溃异常”也归为“页面卡顿”。这样的话就可以统一在某些行为不及预期时上报它们。

以上这些已经属于“错误上报”的范畴了。而我认为,一定要区分开错误上报和数据埋点(也叫埋点上报),这两者有本质区别和各自界定分明的作用场景。

页面崩溃这种行为通常是两种场景导致的:

  1. 过长时间占用JS线程(我们可以把它叫做“主线程”),比如无限循环,触发了浏览器的保护策略;
  2. 内存不足

这么看来页面崩溃就是一个“过火了”的“页面卡顿”。

在这两种场景中,毫无疑问主线程被阻塞,因此对崩溃的监控只能在独立于 JS 主线程的 Worker 线程中进行,我们可以采用 Web Worker 心跳检测的方式来对主线程进行不断的探测,如果主线程崩溃,就不会有任何响应,就直接进行崩溃异常的上报。
比如我们可以这么设置:
对JS 主线程:固定时间间隔向 Web Worker 发送心跳
Web Worker线程:

  • 每隔固定时间检查是否收到心跳(这个间隔和主线程发送心跳的间隔一致);
  • 超过一定时间(间隔时间+n秒)未收到心跳,则认为页面崩溃。
  • 检测到崩溃后,通过 http 请求进行异常上报。

上面的流程是以主线程优先。当然,你也可以换一种思路:

// 主线程
var worker = new Worker('worker.js');

// 父给子传一个初始时候的标志位
worker.postMessage(-1);
worker.onmessage = function(e) 
	//收到worker线程传来的消息
    console.log('Message received from worker', e.data);
    worker.postMessage(e.data);

// 子线程
let date_begin = null;
let dTip = 0;
let newTip = 0;
let new_led = 0;
setInterval(()=> 
    if(!newTip && date_begin || !new_led) 
        // 被认为是崩溃
     else 
        new_led = 0;
        postMessage(++dTip);
    
,2000)
onmessage = function(e) 
    let d = Date.now();
    if(e.data < 0) 
        newTip = 1; //修改标志位确认符
        date_begin = d; //初始化时间
        return
    
    if(d - date_begin > 4000) 
        // 被认为是崩溃
     else 
        date_begin = d;
        new_led = 1;
    

也可以用socket,不过没啥必要,又不是高频强交互行为。而且这里都直接用公司内部封装好的错误上报API了吧。不过像是服务端状态改变实时通知可以试试在 webworker 中使用socket,不过,为什么不试试http/2的 SSE 呢?

除了页面卡顿。前端监控还应涉及视觉交互请求资源、环境、稳定性、网络等方方面面,才能为用户体验打造一个良好的基础。

以上是关于前端监控和页面卡顿的主要内容,如果未能解决你的问题,请参考以下文章

前端 监控

文章学习监控网页卡顿崩溃

字节跳动 iOS Heimdallr 卡死卡顿监控方案与优化之路

前端页面卡顿?或是DOM操作惹的祸,需优化代码

Flutter卡顿问题的监控与思考

前端 页面卡顿加载慢是怎么回事