使用 Fetch Priority API 优化资源加载

Fetch Priority API 可指示资源相对于浏览器的优先级。它可以实现最佳加载和改进核心网页指标。

Addy Osmani
Addy Osmani
Leena Sohoni
Leena Sohoni
Patrick Meenan
Patrick Meenan

浏览器支持

  • Chrome:102。 <ph type="x-smartling-placeholder">
  • Edge:102。 <ph type="x-smartling-placeholder">
  • Firefox:不支持。 <ph type="x-smartling-placeholder">
  • Safari:17.2. <ph type="x-smartling-placeholder">

来源

当浏览器解析网页并开始发现和下载图片、脚本或 CSS 等资源时,会为其分配提取 priority,以便以最佳顺序下载这些资源。资源的优先级通常取决于资源的内容及其在文档中的位置。例如,视口内图片的优先级可能为 High,而对于在 <head> 中使用 <link> 且会提前加载且会阻塞渲染的 CSS,其优先级可能是 Very High。浏览器非常擅长分配优先级,这些优先级能发挥良好的作用,但并不是在所有情况下都是最优的。

本页面介绍了 Fetch Priority API 和 fetchpriority HTML 属性,您可以通过该属性提示资源(highlow)的相对优先级。提取优先级有助于优化核心网页指标。

摘要

“提取优先级”可在以下几个关键方面提供帮助

  • 通过在图片元素上指定 fetchpriority="high" 来提高 LCP 图片的优先级,从而更快地触发 LCP 图片。
  • 使用比当前最常见的黑客手段(为 async 脚本插入 <link rel="preload">)更好的语义,提高了 async 脚本的优先级。
  • 降低后部正文脚本的优先级,以便更好地对图片进行排序。
。 <ph type="x-smartling-placeholder">
</ph> 对 Google 机票首页上的两次测试进行比较的幻灯影片视图。在底部,“抓取优先级”用于提升主打图片的优先级,从而使 LCP 时间缩短 0.7 秒。
在 Google 机票测试中获得优先级,将 Largest Contentful Paint 从 2.6 秒提升到 1.9 秒。

过去,使用预加载预连接,开发者对资源优先级的影响有限。借助预加载,您可以在浏览器自然发现的关键资源之前提前加载这些资源。这对于难以发现的资源尤其有用,例如样式表中包含的字体、背景图片或从脚本加载的资源。预先连接有助于预热到跨源服务器的连接,并有助于改进首字节时间等指标。当您知道来源,但不一定知道所需资源的确切网址时,这会非常有用。

提取优先级是对这些资源提示的补充。它是基于标记的信号,通过 fetchpriority 属性提供,开发者可以使用它来指示特定资源的相对优先级。您还可以通过 JavaScript 和 Fetch API(具有 priority 属性)使用这些提示,以影响为数据提取资源的优先级。提取优先级也可以作为预加载的补充。采用 Largest Contentful Paint 图片,这在预加载时仍将获得低优先级。如果图片被其他早期的低优先级资源推回,则使用“提取优先级”功能有助于图片快速加载。

资源优先级

资源下载顺序取决于为浏览器分配的 网页上的每项资源影响优先级计算的因素 逻辑包括:

  • 资源的类型,例如 CSS、字体、脚本、图片和第三方资源。
  • 文档引用资源的位置或顺序。
  • 是否在脚本中使用了 asyncdefer 属性。

下表显示了 Chrome 如何确定大多数资源的优先级和排序:

<ph type="x-smartling-placeholder">
  在布局阻塞阶段加载 在布局阻塞阶段每次加载一个
Blink
优先级
VeryHigh 中等 VeryLow
DevTools
Priority
最高 中等 最低
主要资源
CSS(早期**) CSS(延迟**) CSS(媒体不匹配***)
脚本(早期** 或不通过预加载扫描器) 脚本(延迟**) 脚本(异步)
字体 字体 (rel=preload)
导入
图片(视口内) 图片(前 5 张图片 > 10,000px2) 映像
媒体(视频/音频)
预取
XSL
XHR(同步) XHR/提取*(异步)

浏览器会按照发现的顺序下载具有相同计算的优先级的资源。在 Chrome 开发者工具的网络标签页下加载网页时,您可以查看分配给不同资源的优先级。(确保通过右键点击表格标题并勾选相应复选框,添加优先级列)。

<ph type="x-smartling-placeholder">
</ph> Chrome 开发者工具中的“Network”标签页,其中列出了多个字体资源。它们均为最高优先级。
BBC 新闻详情页面中资源 type = "font" 的优先级
<ph type="x-smartling-placeholder">
</ph> Chrome 开发者工具中的“Network”标签页,其中列出了多个字体资源。它们混合了“低”和“高”优先级。
BBC 新闻详情页面中资源 type = "script" 的优先级

当优先级发生变化时,您可以在大请求行设置或提示中同时看到初始优先级和最终优先级。

<ph type="x-smartling-placeholder">
</ph> Chrome 开发者工具的“Network”标签页。“大请求行”已勾选“优先级”列,其中第一张的优先级为“高”,下面显示不同的初始优先级为“中”。提示中也会显示相同的选项。
开发者工具中的优先级更改

在什么情况下,您需要使用“提取优先级”设置?

现在,您已经了解了浏览器的优先次序逻辑,接下来可以通过调整网页的下载顺序来优化其性能和核心网页指标了。以下示例展示了您可以通过更改来影响资源下载的优先级:

  • 按照您希望浏览器下载的顺序放置 <script><link> 等资源标记。具有相同优先级的资源通常按照发现的顺序进行加载。
  • 使用 preload 资源提示尽早下载必要的资源,尤其是对于浏览器不易发现的资源。
  • 使用 asyncdefer 下载脚本,而不会屏蔽其他资源。
  • 延迟加载非首屏内容,以便浏览器能够将可用带宽用于更重要的首屏资源。

这些技术有助于控制浏览器的优先级计算,从而提高性能和核心网页指标。例如,如果预加载了某个关键背景图片,系统可以更早地发现它,从而改进了 Largest Contentful Paint (LCP)。

有时,这些句柄可能不足以为您的应用优化资源优先级。以下是“提取优先级”功能可能对您有所帮助的一些场景:

  • 您有多个首屏图片,但并非所有图片都具有相同的优先级。例如,在图片轮播界面中,只有第一张可见图片需要更高的优先级,而其他(通常在屏幕外)图片最初可以设置为具有较低的优先级。
  • 视口内的图像通常从 Low 优先级开始。布局完成后,Chrome 会发现这些广告素材位于视口内,并提高其优先级。这通常会显著增加加载关键图片(例如主打图片)的延迟。在标记中提供提取优先级,可让图片从优先级为 High 时开始加载,从而更早开始加载。为了在一定程度上自动执行此操作,Chrome 将前五张较大的图片的优先级设为 Medium,这有助于解决该问题,但显式 fetchpriority="high" 则更好。

    若要及早发现添加为 CSS 背景的 LCP 图片,仍需要预加载。提升背景图片的优先级,在预加载中包含 fetchpriority='high'
  • 将脚本声明为 asyncdefer 即指示浏览器异步加载它们。不过,正如优先级表格中所示,这些脚本也被分配了“低”优先级优先级。您不妨提高这些脚本的优先级,同时确保可以异步下载,尤其是对于对于用户体验至关重要的脚本。
  • 如果您使用 JavaScript fetch() API 异步提取资源或数据,浏览器会为其分配 High 优先级。您可能希望以较低优先级运行某些提取,尤其是当您将后台 API 调用与响应用户输入的 API 调用混合使用时。将后台 API 调用标记为 Low 优先级,将交互式 API 调用标记为 High 优先级。
  • 浏览器会为 CSS 和字体分配 High 优先级,但其中一些资源可能比其他资源更重要。您可以使用“提取优先级”来降低非关键资源的优先级(请注意,早期的 CSS 会阻塞渲染,因此通常应设为 High 优先级)。

fetchpriority 属性

使用 fetchpriority HTML 属性,为使用 linkimgscript 标记下载的资源(例如 CSS、字体、脚本和图片)指定下载优先级。它可以采用以下值:

  • high:该资源具有更高的优先级,您希望浏览器比平常高优先级,只要浏览器自身的启发法不会阻止这种情况发生。
  • low:该资源具有较低的优先级,您希望浏览器在其启发法允许的情况下再次降低该资源的优先级。
  • auto:默认值,可让浏览器选择合适的优先级。

以下示例说明了如何在标记中使用 fetchpriority 属性以及等效的 priority 属性。

<!-- We don't want a high priority for this above-the-fold image -->
<img src="/images/in_viewport_but_not_important.svg" fetchpriority="low" alt="I'm an unimportant image!">

<!-- We want to initiate an early fetch for a resource, but also deprioritize it -->
<link rel="preload" href="/js/script.js" as="script" fetchpriority="low">

<script>
  fetch('https://example.com/', {priority: 'low'})
  .then(data => {
    // Trigger a low priority fetch
  });
</script>

浏览器优先级和 fetchpriority 的影响

如下表所示,您可以将 fetchpriority 属性应用于不同的资源,以提高或降低这些资源的计算优先级。每行中的 fetchpriority="auto" (◉) 表示相应资源类型的默认优先级。(还可以 Google 文档的形式提供)。

<ph type="x-smartling-placeholder">
  在布局阻塞阶段加载 在布局阻塞阶段一次加载一个
Blink
优先级
VeryHigh 中等 VeryLow
DevTools
Priority
最高 中等 最低
主要资源
CSS(早期**) ⬆◉
CSS(延迟**)
CSS(媒体不匹配***) ⬆*** ◉⬇
脚本(早期** 或不通过预加载扫描器) ⬆◉
脚本(延迟**)
脚本(异步/延迟) ◉⬇
字体
字体 (rel=preload) ⬆◉
导入
图片(视口中 - 布局后) ⬆◉
图片(前 5 张图片 > 10,000px2)
映像 ◉⬇
媒体(视频/音频)
XHR(同步)- 已弃用
XHR/提取*(异步) ⬆◉
预取
XSL

fetchpriority 会设置相对优先级,这意味着它会将默认优先级提高或降低适当量,而不是明确将优先级设置为 HighLow。这通常会导致 HighLow 优先级,但并不总是如此。例如,具有 fetchpriority="high" 的关键 CSS 会保留“非常高”/“最高”并且对这些元素使用 fetchpriority="low" 会保留“High”(高)优先级。这两种情况都不涉及将优先级明确设置为 HighLow

使用场景

如果您想为浏览器提供关于使用什么优先级提取资源的额外提示,请使用 fetchpriority 属性。

提高 LCP 图片的优先级

您可以指定 fetchpriority="high" 来提升 LCP 或其他关键映像的优先级。

<img src="lcp-image.jpg" fetchpriority="high">

以下比较显示了 Google 机票页面,在加载和不使用提取优先级的情况下加载了 LCP 背景图片。将优先级设为“高”后,LCP 从 2.6 秒提高到 1.9 秒

<ph type="x-smartling-placeholder">
</ph>
使用 Cloudflare 工作器通过提取优先级重写 Google 机票页面进行了一项实验。

使用 fetchpriority="low" 可降低不十分重要的首屏图片(例如图片轮播界面中的屏幕外图片)的优先级。

<ul class="carousel">
  <img src="img/carousel-1.jpg" fetchpriority="high">
  <img src="img/carousel-2.jpg" fetchpriority="low">
  <img src="img/carousel-3.jpg" fetchpriority="low">
  <img src="img/carousel-4.jpg" fetchpriority="low">
</ul>

虽然图片 2-4 将不在视口范围内,但它们可能会被视为“足够接近”以将其提升为 high,并且即使添加了 load=lazy 属性也会加载。因此,fetchpriority="low" 是正确的解决方案。

在之前针对 Oodle 应用的实验中,我们使用了此参数降低加载时不显示的图片的优先级。将网页加载时间缩短了 2 秒。

<ph type="x-smartling-placeholder">
</ph> 在 Oodle 应用的图片轮播界面中使用提取优先级时的对照比较。在左侧,浏览器设置了轮播图片的默认优先级,但与右侧示例相比,右侧示例仅对第一张轮播图片设置了较高的优先级,后者的下载和绘制速度会慢大约 2 秒。 <ph type="x-smartling-placeholder">
</ph> 仅为第一张轮播图片使用高优先级可加快网页加载速度。

降低预加载资源的优先级

如需阻止预加载的资源与其他关键资源竞争,您可以降低其优先级。此方法适用于图片、脚本和 CSS。

<!-- Lower priority only for non-critical preloaded scripts -->
<link rel="preload" as="script" href="critical-script.js">
<link rel="preload" as="script" href="non-critical-script.js" fetchpriority="low">

<!-- Preload CSS without blocking render, or other resources -->
<link rel="preload" as="style" href="theme.css" fetchpriority="low" onload="this.rel='stylesheet'">

重新排定脚本的优先级

网页需要具备互动性的脚本应能快速加载,但不应阻碍其他更关键、阻碍呈现的资源。您可以将这类应用标记为async,并为其设置高优先级。

<script src="async_but_important.js" async fetchpriority="high"></script>

如果脚本依赖于特定的 DOM 状态,则您不能将其标记为 async。但是,如果它们稍后在页面上运行,您可按照较低的优先级加载它们:

<script src="blocking_but_unimportant.js" fetchpriority="low"></script>

这仍会在到达此脚本时阻止解析器,但允许优先处理此脚本之前的内容。

如果需要已完成的 DOM,另一种方法是使用 defer 属性(该属性在 DOMContentLoaded 之后依次运行),甚至使用页面底部的 async

降低非关键数据提取的优先级

浏览器以高优先级执行 fetch。如果您有多个可能同时触发的提取操作,则可对较重要的数据提取使用高默认优先级,并降低不太重要的数据的优先级。

// Important validation data (high by default)
let authenticate = await fetch('/user');

// Less important content data (suggested low)
let suggestedContent = await fetch('/content/suggested', {priority: 'low'});

“提取优先级”实现说明

“提取优先级”在特定用例中可以提高性能,但在使用“提取优先级”时需要注意以下几点:

  • fetchpriority 属性是一个提示,而不是指令。浏览器会尝试遵循开发者的偏好设置,但也可以为资源优先级应用资源优先级偏好设置来解决冲突。
  • 不要将“提取优先级”与“预加载”混淆:

    • 预加载是一项强制性提取操作,而不是提示。
    • 预加载可让浏览器提前发现资源,但仍会以默认优先级提取资源。相反,抓取优先级对提高可检测性没有帮助,但可让您提高或降低抓取优先级。
    • 观察和衡量预加载的效果通常比优先级更改的效果更容易。

    提取优先级可以通过提高优先级的粒度来补充预加载。如果您已为 LCP 图片的 <head> 优先指定预加载项之一,则high提取优先级可能不会显著改善 LCP。但是,如果预加载发生在其他资源加载之后,high 提取优先级可以进一步提高 LCP。如果关键图片是 CSS 背景图片,请使用 fetchpriority = "high" 预加载该图片。

  • 在有更多资源竞争可用网络带宽的环境中,优先考虑的加载时间更为相关。这常用于无法并行下载的 HTTP/1.x 连接,或带宽较低的 HTTP/2 或 HTTP/3 连接。在这些情况下,确定优先次序有助于解决瓶颈问题。

  • CDN 不会以相同的方式实现 HTTP/2 优先级,对于 HTTP/3 也是如此。即使浏览器通过“提取优先级”来传达优先级,CDN 可能不会按指定顺序重新设定资源的优先级。这使得测试抓取优先级变得困难。优先级既适用于浏览器内部,也适用于支持优先级的协议(HTTP/2 和 HTTP/3)。但对于与 CDN 或源站支持无关的内部浏览器优先级设置,您还是可以使用“提取优先级”功能,因为当浏览器请求资源时,优先级通常会改变。例如,当浏览器处理关键 <head> 项时,系统通常会阻止请求图片等低优先级资源。

  • 您可能无法在最初的设计中引入提取优先级作为最佳做法。在开发周期的后期,您可以在网页上为不同资源指定优先级,如果它们与您的预期不一致,则可以引入“提取优先级”以做进一步优化。

开发者应将预加载用于其预期用途,即预加载解析器未检测到的资源(字体、导入内容、背景 LCP 图片)。preload 提示的位置会影响资源的预加载时间。

提取优先级决定着在提取资源时应如何提取资源。

预加载功能的使用提示

使用预加载时,请注意以下几点:

  • 在 HTTP 标头中添加预加载项会让它在加载顺序中的所有其他项之前。
  • 通常,对于优先级不低于 Medium 的任何项,预加载会按照解析器获取这些 API 的顺序进行加载。如果您要在 HTML 的开头添加预加载项,请务必谨慎。
  • 字体预加载可能在字体的末尾或正文的开头效果最佳。
  • 导入预加载项(动态 import()modulepreload)应在需要导入的脚本代码之后运行,因此请确保先加载或解析脚本,以便在其依赖项加载时对其进行评估。
  • 默认情况下,映像预加载项具有 LowMedium 优先级。相对于异步脚本和其他优先级较低或优先级最低的代码对这些代码进行排序。

历史记录

2018 年,我们首先在 Chrome 中以源试用的形式对“提取优先级”进行了实验,并在 2021 年再次使用 importance 属性对“提取优先级”进行了实验。当时称为优先级提示。之后,作为网络标准流程的一部分,对于 HTML,该接口已更改为 fetchpriority;对于 JavaScript 的 Fetch API,该接口已更改为 priority。为减少混淆,现在我们将此 API 提取优先级称为“API Fetch Priority”。

总结

开发者可能会对“提取优先级”和预加载行为中的修复以及近期对 Core Web Vitals 和 LCP 的关注感兴趣。现在,它们具有额外的旋钮,可用于实现首选的加载序列。