我们打造效果数据分析的方式和原因

Chrome 102 中,您会在开发者工具中看到一个新的实验性面板,即性能数据分析。在这篇博文中,我们将讨论我们一直在开发新面板的原因,以及我们面临的技术挑战和在此过程中做出的决策。

ALT_TEXT_HERE

为什么要再建一个小组?

(如果您尚未观看过,我们发布了一段视频,介绍了为何要构建“效果洞见”面板,以及如何利用该面板获取有关网站效果的可据以采取行动的洞见。)

如果您想在一个位置查看网站的所有数据,现有的“效果”面板是一个很好的资源,但我们认为它可能有点过于复杂。如果您不是性能专家,则很难确切知道要查找什么以及录制的相关部分。

进入“洞察”面板,您可以在其中查看轨迹的时间轴并检查数据,还可以获得一份便捷的列表,其中列出了开发者工具认为值得深入研究的主要“洞察”。“数据洞见”会找出渲染阻塞请求、布局偏移和长时间任务等问题,这些问题都会对网站的网页加载性能(尤其是网站的 Core Web Vital (CWV) 得分)产生负面影响。除了标记问题之外,Performance Insights 还会为您提供可行的建议,以帮助您提高 CWV 得分,并提供指向更多资源和文档的链接。

面板中的反馈链接

此面板为实验性功能,我们期待您的反馈!如果您遇到任何 bug,或者有您认为有助于提升网站性能的功能请求,请告诉我们。

我们如何构建效果分析

与开发者工具的其余部分一样,我们使用 TypeScript 构建了性能洞见,并使用 lit-html 支持的 Web 组件来构建用户界面。性能数据分析的不同之处在于,其主要界面是 HTML canvas 元素,时间轴绘制在此画布上。很多复杂性都源于管理此画布:不仅要在正确的位置绘制正确的细节,还要管理鼠标事件(例如:用户点击了画布上的哪个位置?用户是否点击了我们绘制的事件?),并确保我们有效地重新渲染画布。

单个画布上的多个轨道

对于给定的网站,我们需要呈现多个“轨道”,每个轨道代表不同的数据类别。例如,“数据洞见”面板默认会显示三个轨道:

随着我们不断在面板中添加功能,预计会有更多曲目被纳入其中。

我们最初的想法是让每个轨道都渲染自己的 <canvas>,这样主视图就会变成多个垂直堆叠的画布元素。这样可以简化轨道级渲染,因为每个轨道都可以单独渲染,并且不会有轨道渲染超出其边界的风险,但遗憾的是,这种方法存在两个主要问题:

canvas 元素的(重新)渲染成本很高;即使画布更大,多个画布的成本也高于一个画布。渲染跨多个轨道(例如,用于标记 FCP 时间等事件的竖线)的任何叠加层都会变得很复杂:我们必须渲染到多个画布上,并确保它们都一起渲染并正确对齐。

为整个界面使用一个 canvas 意味着我们需要弄清楚如何确保每个轨道都以正确的坐标呈现,并且不会溢出到另一个轨道中。例如,如果某个轨道的高度为 100 像素,我们不能允许它渲染高度为 120 像素的内容,并让该内容溢出到下方的轨道中。为了解决这个问题,我们可以使用 clip。在呈现每个轨道之前,我们先绘制一个表示可见轨道窗口的矩形。这样可确保在这些边界之外绘制的任何路径都会被画布剪裁。

canvasContext.beginPath();
canvasContext.rect(
    trackVisibleWindow.x, trackVisibleWindow.y, trackVisibleWindow.width, trackVisibleWindow.height);
canvasContext.clip();

我们也不希望每个轨道都必须知道其垂直位置:每个轨道都应像在 (0, 0) 处渲染一样渲染自身,并且我们有一个更高级别的组件(我们称之为 TrackManager)来管理整体轨道位置。这可以通过 translate 实现,该函数可按给定的 (x, y) 位置平移画布。例如:

canvasContext.translate(0, 10); // Translate by 10px in the y direction
canvasContext.rect(0, 0, 10, 10); // draw a rectangle at (0, 0) that’s 10px high and wide

尽管 rect 代码将位置设置为 0, 0,但应用的总平移会使矩形在 0, 10 处呈现。这样一来,我们就可以按轨道进行处理,就像在 (0, 0) 处渲染一样,并让轨道管理器在渲染每个轨道时进行转换,以确保每个轨道都正确渲染在上一轨道下方。

轨道和精彩集锦的屏幕外画布

Canvas 渲染的成本相对较高,我们希望确保您在使用“数据洞见”面板时,该面板始终保持流畅且响应迅速。有时,您无法避免必须重新渲染整个画布:例如,如果您更改缩放级别,我们必须重新开始并重新渲染所有内容。Canvas 重新渲染的开销尤其大,因为您无法真正只重新渲染其中的一小部分,而是需要擦除整个 Canvas 并重新绘制。这与 DOM 重新渲染不同,在 DOM 重新渲染中,工具可以计算所需的最低工作量,而无需移除所有内容并重新开始。

我们在突出显示方面遇到了视觉问题。当您将鼠标悬停在窗格中的指标上时,系统会在时间轴上突出显示这些指标;同样,如果您将鼠标悬停在特定事件的分析上,系统会在该事件周围绘制蓝色边框。

此功能最初是通过检测鼠标在触发突出显示的元素上的移动来实现的,然后直接在主画布上绘制突出显示效果。但当我们必须移除突出显示的内容时,唯一的方法是重新绘制所有内容!我们无法仅重新绘制突出显示区域(除非进行巨大的架构更改),但仅因为要移除一个项目周围的蓝色边框就重新绘制整个画布,感觉有点过头了。如果您快速将鼠标移至不同项目上,以触发多个连续的高亮显示,该功能也会出现视觉延迟。

为了解决这个问题,我们将界面拆分为两个屏幕外画布:“主”画布(用于渲染轨道)和“精彩集锦”画布(用于绘制精彩集锦)。然后,通过将这些画布复制到屏幕上对用户可见的单个画布上来进行渲染。我们可以对画布上下文使用 drawImage 方法,该方法可以将另一个画布作为其来源。

这样做意味着,移除突出显示内容不会导致系统重绘主画布:相反,我们可以清除屏幕上的画布,然后将主画布复制到可见画布上。复制画布的开销很低,但绘制的开销很高;因此,通过将突出显示内容移到单独的画布上,我们可以在开启和关闭突出显示功能时避免这种开销。

经过全面测试的轨迹解析

从头开始构建新功能的一大优势在于,您可以反思之前做出的技术选择并进行改进。我们希望改进的一点是将代码明确拆分为两个几乎完全不同的部分:

解析轨迹文件并提取所需的数据。 渲染一组轨道。

将解析(第 1 部分)与界面工作(第 2 部分)分开,使我们能够构建可靠的解析系统;每个轨迹都通过一系列负责不同问题的 Handler 运行:LayoutShiftHandler 计算布局偏移所需的所有信息,而 NetworkRequestsHandler 专门负责提取网络请求。这种显式解析步骤(其中不同的处理程序负责处理轨迹的不同部分)也很有益:轨迹解析可能会非常复杂,能够一次专注于一个问题有助于简化流程。

我们还能够在开发者工具中录制轨迹,保存轨迹,然后将其加载到测试套件中,从而全面测试轨迹解析。这非常棒,因为我们可以使用真实轨迹进行测试,而无需构建大量可能过时的虚假轨迹数据。

针对画布界面的屏幕截图测试

继续说测试,我们通常通过将前端组件渲染到浏览器中来测试它们,并确保它们的行为符合预期;我们可以调度点击事件来触发更新,并断言组件生成的 DOM 是正确的。这种方法对我们来说效果不错,但在考虑渲染到画布时会失效;我们无法检查画布并确定绘制的内容!因此,我们通常先渲染再查询的方法并不适用。

为了实现一定的测试覆盖率,我们转向了屏幕截图测试。每项测试都会启动一个画布,渲染我们要测试的轨道,然后截取画布元素的屏幕截图。然后,此屏幕截图会存储在我们的代码库中,未来的测试运行会将存储的屏幕截图与它们生成的屏幕截图进行比较。如果屏幕截图不同,测试将失败。我们还提供了一个标志,用于在有意更改渲染并需要更新测试时运行测试并强制更新屏幕截图。

屏幕截图测试并不完美,而且有点粗略;您只能测试整个组件是否按预期呈现,而无法进行更具体的断言。最初,我们曾过度使用屏幕截图测试,以确保每个组件(HTML 或画布)都能正确呈现。这导致我们的测试套件运行速度大幅下降,并导致出现以下问题:细微的几乎无关的界面调整(例如细微的颜色变化或在项之间添加一些边距)会导致多个屏幕截图失败,需要更新。现在,我们已减少屏幕截图的使用,仅将其用于基于画布的组件,到目前为止,这种平衡对我们来说效果不错。

总结

对于团队而言,构建新的“性能数据分析”面板是一次非常愉快且富有教育意义的体验。我们学习了有关轨迹文件、使用画布等方面的许多知识。我们希望您喜欢使用新面板,并期待收到您的反馈。

如需详细了解“性能分析数据”面板,请参阅性能分析数据:获取有关网站性能的实用分析数据

下载预览渠道

不妨考虑使用 Chrome Canary 版开发者版Beta 版作为默认开发浏览器。通过这些预览渠道,您可以访问最新的 DevTools 功能,测试前沿的 Web 平台 API,并在用户发现问题之前帮助您找到网站上的问题!

与 Chrome 开发者工具团队联系

您可以使用以下选项讨论新功能、更新或与开发者工具相关的任何其他内容。