前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前端性能优化--卡顿监控方案

前端性能优化--卡顿监控方案

原创
作者头像
被删
发布2024-01-26 08:36:47
4070
发布2024-01-26 08:36:47
举报

卡顿大概是前端遇到的问题的最棘手的一个,尤其是卡顿产生的时候常常无法进行其他操作,甚至控制台也打开不了。

但是这活落到了咱们头上,老板说啥就得做啥。能本地复现的我们还能打开控制台,打个断点或者录制 Performance 来看看到底哪些地方占用较大的耗时。如果没法本地复现呢?

卡顿检测

首先,我们来看看可以怎么主动检测卡顿的出现。

卡顿,顾名思义则是代码执行产生长耗时,导致浏览器无法及时响应用户的操作。那么,我们可以基于不同的方案,来监测当前页面响应的延迟。

Worker 心跳方案

对应浏览器来说,由于 JavaScript 是单线程的设计,当卡顿发生的时候,往往是由于 JavaScript 在执行过长的逻辑,常见于大量数据的遍历操作,甚至是进入死循环。

利用这个特效,我们可以在页面打开的时候,就启动一个 Worker 线程,使用心跳的方式与主线程进行同步。假设我们希望能监测 1s 以上的卡顿,我们可以设置主线程每间隔 1s 向 Worker 发送心跳消息。(当然,线程通讯本身需要一些耗时,且 JavaScript 的计时器也未必是准时的,因此心跳需要给予一定的冗余范围)

由于页面发生卡顿的时候,主线程往往是忙碌状态,我们可以通过 Worker 里丢失心跳的时候进行上报,就能及时发现卡顿的产生。

但是其实 Worker 更多时候用于检测网页崩溃,用来检测卡顿的效果其实还不如使用window.requestAnimationFrame,因为线程通信的耗时和延迟导致该方案不大准确。

window.requestAnimationFrame 方案

前面前端性能优化--卡顿篇有简单提到一些卡顿的检测方案,市面上大多数的方案也是基于window.requestAnimationFrame方法来检测是否有卡顿出现。

window.requestAnimationFrame()会在浏览器下次重绘之前调用,常常用来更新动画。这是因为setTimeout/setInterval计时器只能保证将回调添加至浏览器的回调队列(宏任务)的时间,不能保证回调队列的运行时间,因此使用window.requestAnimationFrame会更合适。

通常来说,大多数电脑显示器的刷新频率是 60Hz,也就是说每秒钟window.requestAnimationFrame会被执行 60 次。因此可以使用window.requestAnimationFrame来监控卡顿,具体的方案会依赖于我们项目的要求。

比如,有些人会认为连续出现 3 个低于 20 的 FPS 即可认为网页存在卡顿,这种情况下我们则针对这个数值进行上报。

除此之外,假设我们认为页面中存在超过特定时间(比如 1s)的长耗时任务即存在明显卡顿,则我们可以判断两次window.requestAnimationFrame执行间超过一定时间,则发生了卡顿。

使用window.requestAnimationFrame监测卡顿需要注意的是,他是一个被十分频繁执行的代码,不应该处理过多的逻辑。

Long Tasks API 方案

熟悉前端性能优化的开发都知道,阻塞主线程达 50 毫秒或以上的任务会导致以下问题:

  • 可交互时间(TTI)延迟
  • 严重不稳定的交互行为 (轻击、单击、滚动、滚轮等) 延迟
  • 严重不稳定的事件回调延迟
  • 紊乱的动画和滚动

因此,W3C 推出 Long Tasks API。长任务(Long task)定义了任何连续不间断的且主 UI 线程繁忙 50 毫秒及以上的时间区间。比如以下常规场景:

  • 长耗时的事件回调
  • 代价高昂的回流和其他重绘
  • 浏览器在超过 50 毫秒的事件循环的相邻循环之间所做的工作

参考 Long Tasks API -- MDN

我们可以使用PerformanceObserver这样简单地获取到长任务:

代码语言:js
复制
var observer = new PerformanceObserver(function (list) {
  var perfEntries = list.getEntries();
  for (var i = 0; i < perfEntries.length; i++) {
    // 分析和上报关键卡顿信息
  }
});
// 注册长任务的观察
observer.observe({ entryTypes: ["longtask"] });

相比requestAnimationFrame,使用 Long Tasks API 可避免调用过于频繁的问题,并且performance timeline的任务优先级较低,会尽可能在空闲时进行,可避免影响页面其他任务的执行。但需要注意的是,该 API 还处于实验性阶段,兼容性还有待完善,而我们卡顿常常发生在版本较落后、性能较差的机器上,因此兜底方案也是十分需要的。

PerformanceObserver 卡顿检测

前面也提到,卡顿产生于用户操作后网页无法及时响应。根据这个原理,我们可以使用PerformanceObserver监听用户操作,检测是否产生卡顿:

代码语言:js
复制
new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    const duration = entry.duration;

    const delay = entry.processingStart - entry.startTime;
    const eventHandlerTime = entry.processingEnd - entry.processingStart;

    console.log(`Total duration: ${duration}`);
    console.log(`Event delay: ${delay}`);
    console.log(`Event handler duration: ${eventHandlerTime}`);
  });
}).observe({type: 'event'});

这种方式的好处是避免频繁在requestAnimationFrame中执行任务,这也是官方鼓励开发者使用的方式,它避免了轮询,且被设计为低优先级任务,甚至可以从缓存中取出过往数据。

但该方式仅能发现卡顿,至于具体的定位还是得配合埋点和心跳进行会更有效,这部分会在下一篇文章中介绍。

查看Github有更多内容噢: https://github.com/godbasin

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 卡顿检测
    • Worker 心跳方案
      • window.requestAnimationFrame 方案
        • Long Tasks API 方案
          • PerformanceObserver 卡顿检测
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档