likes
comments
collection
share

[译]Fetch Priority 和优化LCP

作者站长头像
站长
· 阅读数 25

原文 《Fetch Priority and optimizing LCP》

原文发布时间:2023 年 1 月 2 日 原文更新时间:2023 年 5 月 2 日

Fetch Priority API 用于向浏览器指示资源的相对优先级。您可以通过在<img><link><script><iframe>元素上添加fetchpriority属性,或通过 Fetch API 上的priority属性来配置优先级。 浏览器的加载过程是复杂的。浏览器主要通过请求的类型和在文档标记中的位置来确定其优先级。例如,在文档的 <head> 中请求的CSS文件将被分配最高优先级,而带有defer属性的 <script> 元素将被分配低优先级。浏览器按照发现资源的顺序下载具有相同优先级的资源。

fetchpriority

fetchpriority属性可用于提示浏览器提高或降低所请求资源的优先级。具有以下三个属性值: high - 相对于默认优先级,该资源更重要 low - 相对于默认优先级,该资源较不重要 auto - 默认值

<img src="/lcp.jpg" alt="A dog" fetchpriority="high" />

在上面的示例中,我们提示浏览器将<img>的优先级设为比默认优先级更重要。 在 fetch 方法的 priority 属性也支持相同的值。

fetch("/api/data.json", { priority: 'high' })

在上述的fetch请求中,我们向浏览器表明该fetch请求的优先级比默认优先级要高。

默认优先级

Fetch Priority API 可以提高或降低资源相对于其默认的优先级。例如,图像在默认情况下始终以low优先级开始,但分配fetchpriority="high"会将它们的优先级提高到high。另一方面,阻塞渲染的样式表默认分配了Highest优先级。分配它fetchpriority="low"会将其优先级降低到high - 但不是lowfetchpriority用于调整资源相对于其默认值的优先级,而不是显式设置其值。 在influence of Fetch Priority on resource prioritization in Chromium文档中记录了不同的资源类型、它们的默认优先级 (◉) 以及使用fetchpriority="high"(⬆) 和fetchpriority="low"(⬇) 时产生的优先级。 请注意,如果发现图像在视口内,则其优先级会提高到High。但是,这可能在加载过程中靠后的阶段发生,如果请求已经发送则可能影响很小或没有影响。使用fetchpriority="high"允许您告诉浏览器以High优先级启动,而不是等待浏览器确定它是否在视口中。

“紧凑模式”(Tight mode)

大多数浏览器分两个阶段下载资源。在初始阶段(Chromium 也将此称为“Tight mode”),浏览器不会下载Low优先级资源,除非少于两个正在传输的请求。 [译]Fetch Priority 和优化LCP 在上面的瀑布图中,您可以看到资源 image-1.jpg 即使它立即被发现,也会等到 style-2.css 完成下载后才开始下载。此时,只有script.js一个资源仍在传输中,这时浏览器开始下载Low优先级图像。 一旦<head>中的所有阻塞脚本都已下载并执行(带有asyncdefer的脚本不呈现阻塞),初始阶段就完成了。即使有两个以上正在传输的请求,浏览器现在也可以根据它们的优先级和它们在标记中出现的顺序继续下载任何剩余的资源。 [译]Fetch Priority 和优化LCP 在上图中,一旦阻塞渲染的JavaScript下载并执行(粉色条),即使这两个 CSS 文件仍在传输中,浏览器也会开始下载图像。黄色垂直线表示 DOM 可交互或者readystatechange事件被触发的时间。

preconnect

如果图像位于不同的域上,则浏览器需要在下载文件之前打开与该域的连接。 [译]Fetch Priority 和优化LCP 这显示在 WebPageTest 图表上,下载前有绿色、橙色和洋红色条。我们可以使用preconnect资源提示更早地开始下载图像。 [译]Fetch Priority 和优化LCP 在上图中,与cdn.glitch.global域的连接在初始阶段打开 - 在浏览器能够开始下载文件之前。一旦浏览器退出初始阶段(黄色垂直线),它就会立即开始下载图像——节省大约 350 毫秒。

preload

如果我们能够使用preconnect资源提示缩短下载时间,我们是否能够使用preload指令进一步缩短下载时间?简洁的回答:不能。 preload 指令允许您通知浏览器有关“晚发现”的关键资源。这对于在样式表或脚本中加载的资源特别有用,例如背景图或字体。在我们的示例中,图像在标记中声明并较早发现,因此预加载几乎没有影响。 [译]Fetch Priority 和优化LCP 在上图中,我们已将preconnect替换为以下内容:

<link
  rel="preload"
  as="image"
  href="https://cdn.glitch.global/.../image-1.jpg"
/>

尽管有预加载,图像仍然不会开始下载,直到少于两个正在运行的请求。

fetchpriority

我们可以使用 Fetch Priority 向浏览器表明 image-1.jpg 比其默认优先级更重要,使用:

<img
  src="https://cdn.glitch.global/.../image-1.jpg"
  fetchpriority="high"
  alt=""
/>

这应该会将图像的初始优先级从Low增加到High,使得图像能在初始阶段被处理。 [译]Fetch Priority 和优化LCP 上面的瀑布图显示, image-1.jpg 在初始阶段与其他关键资源同时被处理。这给了我们迄今为止最大的改进。

Firefox

Firefox 使用类似的启发式方法来确定应在初始阶段加载哪些资源。然而,与基于 Chromium 的浏览器不同,它不会开始下载任何Low优先级资源,直到<head>中的所有 JavaScript 都被下载并执行 - 即使只有一个High优先级请求正在运行。 [译]Fetch Priority 和优化LCP 以上截图来自Firefox Web开发者工具,显示在下载和执行脚本(第2行)以及页面变得可交互之后,图片资源(第5至8行)被获取的时间点,用蓝色的垂直线表示。 当 Chrome 等待在<head>中声明的 JavaScript 下载并执行时,Firefox 等待所有在图像元素之前声明的渲染阻塞 JavaScript——即使这些是在<head>之外声明的。 Firefox 还不支持 fetchpriority ,但是,我们可以使用 preload 指令提高 image-1.jpg 的优先级。 [译]Fetch Priority 和优化LCP 在上面的屏幕截图中,文件 image-1.jpg 与其他资源并行获取。这类似于我们在 Google Chrome 上添加fetchpriority="high"时看到的行为。

Safari

iOS 和 macOS 上的 Safari 也有一个初始阶段,尽管它的行为不同于 Chrome 和 Firefox。 低优先级资源在正在传输中的请求少于两个时开始获取。这不依赖于readystatechange事件,即使在没有任何阻止渲染的JavaScript的页面上,浏览器也会等待至少有一个正在传输中的请求。 [译]Fetch Priority 和优化LCP 上图显示了从Safari的Web Inspector中获取的截图,直到style-1.css完成下载并且正在传输中的请求少于两个时,图像才开始下载。 在 Safari 上,初始阶段仅适用于同源资源。如果Low优先资源是从不同的域加载的,它们将在被发现后立即获取。 [译]Fetch Priority 和优化LCP 在上面的截图中,跨域图像被立即获取,而不是等待High优先级资源完成下载。 proload指令不会影响资源的优先级。然而,将<link rel="preload">指令放置在高优先级请求之前会导致它更早地下载;因为在发现时正在传输中的请求少于两个。这与其他浏览器上的行为相同,在大多数情况下,我建议不要将proload指令放置在高优先级资源之上,因为阻塞渲染的CSS应该具有优先权。 [译]Fetch Priority 和优化LCP 此图中,Low优先级文件 image-1.jpg 在High优先级 style-1.css 文件之前开始下载,因为在文档标记中<link rel="preload">位于其上方。

将 preload 与 fetchpriority 组合

到目前为止,Fetch Priority 仅在基于 Chromium 的浏览器上受支持,但是,它在不识别fetchpriority属性的浏览器上会进行降级处理。这允许我们将preload指令与 Fetch Priority 结合起来。

<link
  rel="preload"
  as="image"
  fetchpriority="high"
  href="https://cdn.glitch.global/.../image-1.jpg"
/>

支持 Fetch Priority 的浏览器将使用分配的fetchpriority预加载资源,而不支持的浏览器将使用 preload 指令。 [译]Fetch Priority 和优化LCP 上图表显示了与之前在<img>元素上包含fetchpriority属性的图表类似的结果。这种方法的优势在于统一处理资源的优先级,无论是在支持Fetch Priority的浏览器上还是在不支持的浏览器上。

fetchpriority的潜在好处

在本节中,我们将研究使用fetchpriority的潜在好处。所有数据均取自HTTP Archive,我们仅考虑使用 HTTP/2 或 HTTP/3 且最大内容绘制 (LCP) 元素为图像的页面。所有查询和结果都是公开的。 注意:HTTP Archive数据是使用Chrome的私有WebPageTest实例收集的。您可以详细了解他们的方法[译]Fetch Priority 和优化LCP 我假设fetchpriority的好处是发现资源的时间和开始下载的时间之间的时间差。我将此称为“opportunity”。因此,如果一个资源发现得早,但浏览器开始下载的时间晚,那么opportunity就更大。 请注意,如果图像是从不同的域提供的,则会在“opportunity”中包括打开连接的时间。 [译]Fetch Priority 和优化LCP 上图绘制了针对 LCP 的opportunity(以毫秒为单位)。opportunity以 100 毫秒为一组进行存储,而大于 1,000 毫秒的任何时间都被分组到一个存储桶中。该图表显示了“opportunity”与 LCP 之间的强相关性 - opportunity越大,LCP 越差。

[译]Fetch Priority 和优化LCP 上图显示了针对LowHigh优先级的移动设备的opportunity分布。在中间值处,High优先级请求的 LCP 图像在被发现后 21 毫秒开始下载,而Low优先级请求的 LCP 图像在 102 毫秒后开始下载。在75%和90%处差异甚至更大。 除了 fetchpriority="High" 之外,如果图像是较晚发现的,例如在使用 CSS background-image 或使用 JavaScript 添加图像时,图像可能具有初始的High优先级。在这些情况下,fetchpriority将无济于事,因为请求已经具有High优先级。 我们可以得出结论,优先考虑 LCP 图像具有明显的好处。opportunity因页面的组成而异。我们已经介绍过,当至少有一个渲染阻塞脚本和两个或多个正在进行的请求时,不会立即获取Low优先级资源。 [译]Fetch Priority 和优化LCP 上图绘制了渲染阻塞资源的数量与opportunity(以毫秒为单位)。直观地说,您的页面拥有的渲染阻塞资源越多,下载 LCP 图像的延迟就越大。

结论

有很大的机会可以通过资源提示和获取优先级来确定 LCP 图像的优先级。即使LCP元素在主文档中立即可发现,许多页面仍会将其排队等待处理。 [译]Fetch Priority 和优化LCP 上图显示,在中等移动网站上,LCP 图像排队等待 98 毫秒,直到浏览器开始下载它。在90% 处LCP 图像排队等待 810 毫秒。使用 Fetch Priority 可以提高 LCP 图像的优先级并减少等待时间。 还有一些案例研究表明,在将fetchpriority="high"添加到 LCP 图像后,Largest Contentful Paint (LCP) 得到了改进。Etsy 的改进幅度为 4%,据报道其他一些改进幅度为 20-30%。 提高资源的优先级通常会以另一个资源为代价,因此应该谨慎使用获取优先级(Fetch Priority)。然而,如果浏览器正在将您的LCP图像排队等待处理,我建议您尝试使用Fetch Priority,看看是否能减少等待时间并改善LCP。

简而言之,

  • 将 LCP 图像托管在与 HTML 文档相同的域中。如果这不可行,请使用preconnect来建立早期连接。
  • LCP 图像应该是文档标记的一部分。如果这不可行,请使用preload告诉浏览器在请求之前下载图像。
  • 尽可能避免阻塞资源。如果您的 LCP 图像以Low优先级下载,请使用fetchpriority提示浏览器更早下载您的图像。
  • 在支持fetchpriority之前,您可以使用preload在 Firefox 上设置 LCP 图像的优先级。使用preload指令时,Safari 不会提前下载图像。

相关链接

Demos Queries & Results Optimizing resource loading with Priority Hints(web.dev) Prioritizing Important Page Resources With Priority Hints(debugbear.com)

备注

此功能最初称为 Priority Hints,但在标准化后更名为 Fetch Priority。