通常这类 benchmark 工具都是在 Node 上执行的,但是我们的 SDK 是个前端监控 SDK,依赖了非常多的浏览器环境对象,我们几乎不可能在 Node 环境去创造或模拟这些对象,我们有没有办法在浏览器里去运行这段脚本,做性能自动化测试呢?
利用 Puppeteer 在浏览器环境中执行 Benchmark由于我们的前端监控依赖浏览器环境,我们可以将上述 benchmark 测试代码打包成 commonjs 之后放入 headless chrome 浏览器中执行,并通过 puppeteer 收集执行结果 。
Puppeteer 是一个 Node 模块,提供了通过 Devtool Protocol 控制 Chrome 或者 Chromium 的能力 。Puppeteer 默认运行 Chrome 的无头版本,也可以通过设置运行 Chrome 用户界面版 。下面是一段方便理解操作 puppeteer 过程的伪代码,仅作参考,实际情况较为复杂,需要等待未完成的异步请求等:
const browser = await puppeteer.launch()const page = await browser.newPage()const cdp = await page.target().createCDPSession()// 用于 benchmark 脚本和 puppeteer 之间的通信,用以收集结果await page.evaluate(() => (window.benchmarks = []))// 将 pushResult 方法暴露给浏览器,来将结果收集到 node 端await page.exposeFunction('pushResult',(result: any) => benchmark.results.push(result))await cdp.send('Profiler.enable')await cdp.send('Profiler.start')// 开始执行 benchmarkawait page.addScriptTag({content: file.toString(),})await Promise.race([timeout, allBenchmarksDone()])// profile 可用于绘制火焰图const { profile } = await cdp.send('Profiler.stop')await page.close()
通过运行以上脚本,我们便可以在无头浏览器中运行我们的性能测试脚本,在测试脚本产出结果后添加调用 pushResult 方法来收集测试结果 。在实际的 benchmark 测试中,我们发现开启性能监听(即运行各个性能监控的 PerformanceObserver.observe 方法)最大耗时达到了21ms,虽然看上去并不久,但若和其他监听同时执行,加上引入业务代码的复杂性和移动端更弱的 CPU 性能,极有可能成为给业务带来 longtask 的罪魁祸首 。性能监控性能成为了瓶颈 。接下来,我们将性能监听一个个拆分,用同样的方式单独测试每一个性能监听的耗时 。在实际的 benchmark 结果中,我们发现 fp、fcp、lcp、cls 监控耗时最大,加在一起超过了10ms,占了一半以上,是我们之后需要重点优化的地方 。除此之外利用 puppeteer 的能力,我们不仅可以得到 benchmark 的结果,还可以获取到整个 benchmark 过程的 profile 数据,利用 speedscope 绘制出函数执行过程中的火焰图:
绘制火焰图的具体实现不在本文讨论范围内,感兴趣的同学可以参考 speedscope 官方文档

文章插图
经验总结扩展阅读
- 四 Selenium4.0+Python3系列 - 常见元素操作(含鼠标键盘事件)
- iPhone14Pro满电无法开机是怎么回事 iPhone14系列糟点有哪些
- iQOO8系列配置_iQOO8系列参数详情
- 30 《吐血整理》高级系列教程-吃透Fiddler抓包教程-Fiddler如何抓取Android7.0以上的Https包-番外篇
- 从0搭建vue3组件库: 如何完整搭建一个前端脚手架?
- 树的邻接矩阵、双亲孩子表示法…… C++ 不知树系列之初识树
- .NET Core C#系列之XiaoFeng.Data.IQueryableX ORM框架
- flutter系列之:永远不用担心组件溢出的Wrap
- 荣耀x20评测_荣耀x20评测表现
- 抛砖系列之redis监控命令