前端监控系列4 | SDK 体积与性能优化实践( 三 )

通过运行以上脚本,我们便可以在无头浏览器中运行我们的性能测试脚本,在测试脚本产出结果后添加调用 pushResult 方法来收集测试结果 。在实际的 benchmark 测试中,我们发现开启性能监听(即运行各个性能监控的 PerformanceObserver.observe 方法)最大耗时达到了21ms,虽然看上去并不久 , 但若和其他监听同时执行,加上引入业务代码的复杂性和移动端更弱的 CPU 性能,极有可能成为给业务带来 longtask 的罪魁祸首 。性能监控性能成为了瓶颈 。接下来,我们将性能监听一个个拆分,用同样的方式单独测试每一个性能监听的耗时 。在实际的 benchmark 结果中,我们发现 fp、fcp、lcp、cls 监控耗时最大,加在一起超过了10ms,占了一半以上,是我们之后需要重点优化的地方 。
除此之外利用 puppeteer 的能力 , 我们不仅可以得到 benchmark 的结果,还可以获取到整个 benchmark 过程的 profile 数据,利用 speedscope 绘制出函数执行过程中的火焰图:

绘制火焰图的具体实现不在本文讨论范围内,感兴趣的同学可以参考 speedscope 官方文档

前端监控系列4 | SDK 体积与性能优化实践

文章插图
此处显示的时间为该用例执行总耗时(单次耗时*次数)
如何衡量异步任务性能?Benny 的 api 是支持异步测试用例的,测量的是每个异步函数从开始执行到 resolve 的时间 。但通常这并不是我们想要的衡量的数据,因为异步任务的执行过程中并不是一直占据着主线程 。对于一些异步的定时任务(例如 SDK 的崩溃检测、卡顿检测、白屏检测),将他们拆解为一系列可测的同步任务能更直观的展示各个阶段的性能耗时 。例如我们 SDK 的前端白屏检测,由一个 mutationObserver 和触发白屏检测的函数组成 。我们可以单独对 mutationObserver 的回调和触发函数做性能衡量 。这两个方法已没有很好的优化方式了 。但是根据 benchmark 结果并结合源码可以发现,性能监控所有指标项的开启均为同步执行,每一项指标都会对页面做事件监听或者 PerformanceObserver 监听,且这些原生监听耗时都在毫秒级 。于是我们对性能做了如下优化:
  1. 性能监控逻辑分片运行,将各项性能指标的监听同步拆为异步,用 requestIdleCallback 做调度并区分优先级 。
  2. 多个性能指标监听同一事件的公用监听器 , 例如 CLS 和 LCP 都需要监听 onBFCacheRestore,让他们只做一次 addEventListener 。
  3. 可以延迟执行的方法延迟执行,例如在高版本的 Chrome 中 PerformanceObserver 是有 buffer 的,可以直接获取到调用之前的性能指标,这些方法调用就可以等待页面完全加载完成之后执行 , 从而尽可能减少对业务页面首屏影响 。
通过 Perfsee 的 Lab 结果分析性能问题以上的 benchmark 流程得到的结果毕竟是一种理想化、单纯的方法调用的性能情况,然而在实际浏览器环境中我们前端监控 SDK 对性能影响有多大呢,对于这一类页面初始化即加载的 SDK 可以通过 Perfsee 的 Lab 功能进行性能衡量 。
Perfsee 是一个针对前端 web 应用在整个研发流程中的性能分析平台 。提供性能分析报告、产物分析报告、源码分析、竞品分析等模块 , 定位与梳理性能问题 , 提供专业的优化方案来渐进地优化产品性能 。Lab 模块性能分析的依据是,使用 headless 浏览器运行用户指定的页面,通过运行时数据的收集,分析并产出关键性能指标分数、网络请求信息、主线程 JS/渲染/Longtask 信息供业务方参考优化 。具体使用说明请查看 http://perfsee.com注意,本文所展示 Perfsee 功能示例为早期版本,并不与开源版本功能和界面完全一致 。
准备基准页面作为对照组我们的目的是衡量 SDK 对业务性能造成的影响,便需要找到一个基准页面作为对比 。此处以 React Server Component Demo 为例作为基准页面 。该应用有以下几个特点:
  1. 容易搭建,一个命令就能跑起来 。
  2. 自身逻辑简单,性能好,SDK 所造成的影响容易被放大观察 。
  3. SPA 应用,含有异步加载的逻辑,更容易探测到监控 SDK 对页面 FCP、LCP 等指标影响 。
  4. 无外部网络请求 , 页面结果稳定不易波动 。
我们修改一下应用的逻辑,能够通过 url 参数注入监控 sdk 脚本,把它部署在服务器上 。接着,我们在 perfsee 平台上配置好基准页面和注入 SDK 的页面这两个 page,并触发一次性能扫描 。
查看 Lab 性能报告我们将没有注入 SDK 的页面作为空白组(empty),注入了 SDK 的页面作为实验组(with-sdk) 。首先我们需要配置好空白组和实验组的 pages 以及 profile,触发一次 snapshot 之后 , 我们得到了多份报告,我们可以点击 compare 将空白组和实验组的数据进行比对 。

推荐阅读