使用优先级提示优化资源加载

948 阅读13分钟

优先级提示可以表示当前资源对于浏览器的相对重要性。它们能够实现最佳加载并改进Core Web Vitals。

当浏览器解析网页并开始发现并下载像图片,脚本,css文件等资源时,它会为它们分配获取权限,并尝试以最佳顺序来下载资源。这些优先级可能取决于资源的类型以及它在文件中的位置。例如,视口内图像可能比早期的<link> 加载具有更高的优先级,内联css的优先级可能非常高。浏览器很擅长分配资源以使网页正常工作,但可能不会在所有情况中都是最佳的优先级。

在本文中,我们将讨论优先级提示和importance属性,importance属性能够让你提示资源的相对重要性(high或low)。优先级提示能够帮助优化网站内核。

img

在谷歌航班测试中,优先级提示将包含内容的图片资源加载速度从2.6s提高到了1.9s

摘要

优先级提示能够帮助的几个关键区域:

  • 通过在图像元素上指定importance="high"来提高 LCP 图像的优先级,从而使 LCP 更快加载。
  • 使用比当前常用的hack更好的语义方式来增加"async"脚本的优先级(为"async"脚本插入<link rel="preload"> )。
  • 降低后期主体脚本的优先级,以便更好地与图像进行排序。

从历史上看,开发人员使用[预加载](web.dev/uses-rel-pr…] (www.w3.org/TR/resource… [第一字节响应时间](web.dev/ttfb/)等指标,并…

优先级提示是一种基于标记的符号(通过importance属性提供),开发人员可以使用该符号来表示特定资源的重要性。您也可以通过 JavaScript 和调用API(developers.google.com/web/updates… 优先级提示是 Chrome 96+ 中的 [原始试用](developer.chrome.com/origintrial… Chrome Beta - 4周后稳定版)。我们希望开发人员能够试用并提供一定的反馈意见。能够保留的功能取决于开发人员的反馈意见。您也可以通过 Chrome 中的标志尝试优先提示。

资源优先级

资源下载序列取决于浏览器对页面上每个资源分配的优先级。不同的因素会影响优先级的计算逻辑。例如,

  • CSS、字体、脚本、图像和第三方资源被分配不同的优先级。
  • 文档中引用资源的位置或顺序也会影响资源的优先级。
  • [预加载](web.dev/uses-rel-pr…
  • 脚本的计算优先级更改"异步"或"延迟"

下表考虑了这些因素,并显示了当前在 Chrome 中对大多数资源的优先级和排序情况。

布局-阻塞布局-阻塞期间加载布局-阻塞期间加载一次
Blink 优先级非常高非常低
开发工具优先级最高最低
主要资源
CSS*** (早期**)CSS*** (后期**)CSS (匹配错误)
脚本 (早期** 或非预加载扫描文件)脚本 (**后期)脚本 (异步)
文字文字 (预加载)
导入
图像 (在视图中)图像
媒体
SVG 文件
预读取
预加载*
XSL
XHR (同步)XHR/提取* (异步)
图标

* 使用"as"预加载或者他们请求的类型的优先级来获取使用"type"。 (例如, 预加载 as="stylesheet" 将使用最高优先级). 没有"as", 他们的行为将表现的像XHR一样。

** "Early" 被定义为在请求任何非预加载图像之前先被请求("late"是在之后)。

*** 媒体类型不匹配的CSS不会被预加载扫描器获取,只有在主解析器到达时才会处理,这通常意味着它将被获取得很晚并且具有"late"优先级。

浏览器按照资源被发现的顺序下载具有相同计算优先级的资源。你可以在ChromeDev Tools Network 选项卡下加载页面时,检查分配给不同资源的优先级。(确保通过右键单击表格标题来检查优先级列)。

img

BBC新闻详情页上type = "font"的优先级

img

BBC新闻详情页上type = "script"的优先级

什么时候你需要优先提示

浏览器优先级逻辑的知识为您提供了一些现有的方式来调整下载顺序。你可以

  1. 根据您要下载它们的顺序放置资源标签,例如<script><link>具有相同优先级的资源通常按照它们被发现的顺序加载。
  2. 使用预加载资源提示 提前下载必要的资源,特别是对于浏览器早期不易发现的资源。
  3. 使用 async or `defer 下载脚本而不阻塞其他资源。
  4. 延迟加载首屏内容,以便浏览器可以将可用带宽用于更重要的首屏资源。

这些技术有助于控制浏览器的优先级计算, 从而提高性能和 Core Web Vitals. 当预加载关键背景图像时,可以更早地发现它,从而改进最大内容绘制 (LCP)。

有时,这些句柄可能不足以为您的应用程序优化资源的优先级。我们可以考虑以下优先级提示可能会有所帮助的场景。

  1. 您有多个首屏图像,但它们不必具有相同的优先级。例如,在图像轮播中,与其他图像相比,只有第一个可见图像需要更高的优先级。

  2. 视口内的图像以低优先级开始。布局完成后,Chrome 发现它们在视口中并提高它们的优先级(不幸的是, 开发工具只显示最终优先级 - WebPageTest 将同时显示两者)。这通常会使加载图像显著延迟。 在标记中提供优先级提示可以让图像以高优先级开始并更早地开始加载。

    请注意,早期发现作为 CSS 背景包含的 LCP 图像仍然需要预加载,并且可以通过在预加载中包含importance='high'来与优先级提示相结合,否则它仍然会以默认的“低”优先级图像开始。

  3. 将脚本声明为asyncdefer告诉浏览器异步加载它们。但是,如上图所示,这些脚本也被分配了“低”优先级。您可能希望在确保异步下载的同时提高它们的优先级,尤其是对于对用户体验至关重要的任何脚本。

  4. 您可以使用 JavaScriptfetch() 异步获取资源或数据。浏览器为 Fetch 分配了高优先级。在某些情况下,您可能不希望以高优先级执行所有提取,而更喜欢使用不同的优先级提示。这在运行后台 API 调用并将它们与响应用户输入的 API 调用(如自动完成)混合时会很有帮助。可以将后台 API 调用标记为低优先级,将交互式 API 调用标记为高优先级。

  5. 浏览器为 CSS 和字体分配了高​​优先级,但这些资源可能并不都同等重要或者被 LCP 所需要。您可以使用优先级提示来降低其中一些资源的优先级。

importance 属性

借助可用作 Origin Trial 的优先提示的实验性功能,您可以使用importance属性提供优先提示。您可以使用属性link, img,script, 和 iframe 标签。当使用支持的标签下载时,该属性允许您指定资源类型的优先级,例如 CSS、字体、脚本、图像和 iframe。重要性属性接受以下三个值之一:

  • high: 您认为该资源具有高优先级,并希望浏览器对其进行优先级排序,只要浏览器的启发式方法不阻止这种情况发生。
  • low: 您认为该资源的优先级较低,并希望浏览器在启发式允许的情况下降低其优先级。
  • auto: 这是您没有偏好的默认值,让浏览器决定适当的优先级。

以下是在标记和脚本中使用重要性属性的几个示例。

<!-- 我们不想给这个首屏图片设置高优先级 -->
<img src="/images/in_viewport_but_not_important.svg" importance="low" alt="I'm an unimportant image!">

<!-- 我们想要尽早获取一个资源,但也要降低其优先级 -->
<link rel="preload" href="/js/script.js" as="script" importance="low">

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

<!-- 这个iframe的第三方内容可以以一个低优先级加载 -->
<iframe src="https://example.com" width="600" height="400" importance="low"></iframe>

当在iframe上设置优先级提示时, 优先级仅应用于 iframe 的主要资源。iframe将使用适用于所有其他资源的相同规则对加载的所有子资源进行优先级排序。

浏览器优先级和importance

您可以将importance 属性应用到不同的资源,如下图所示,以潜在地增加或减少它们的计算优先级。Importance = auto (◉) 在每行中 表示该类型资源的默认优先级。

布局-阻塞布局-阻塞期间加载布局-阻塞期间加载一次
Blink 优先级非常高非常低
开发工具优先级最高最低
主要资源
CSS*** (早期**)⬆◉
CSS*** (后期**)
脚本 (早起** 或非预加载扫描文件)⬆◉
脚本*** (后期**)
脚本 (异步/延迟)◉⬇
文字
文字 (预加载)⬆◉
导入
图像 (在视图中)⬆◉
图像◉⬇
媒体 (视频/音频)◉⬇
SVG 文件◉⬇
XHR (同步) - 弃用
XHR/提取* (异步)⬆◉
预加载*⬆◉
预提取
图标
XSL

* 使用"as"预加载或者他们请求的类型的优先级来获取使用"type"。(例如, 预加载 as="stylesheet" 将使用最高的优先级). 没有 "as", 他们的行为将表现的像XHR一样。

** "Early" 被定义为在请求任何非预加载图像之前先被请求("late"是在之后)。

*** 媒体类型不匹配的CSS不会被预加载扫描器获取,只有在主解析器到达时才会处理,这通常意味着它将被获取得很晚并且具有"late"优先级。

◉: importance="auto"

⬆: importance="high"

⬇: importance="low"

视口内的图像以低优先级开始,然后在布局时被提升到高优先级。通过在标记中使用importance标记它,它可以立即从高优先级开始并加载得更快。

用例

您可以使用该importance属性来解决可能需要优先级提示的场景。

增加 LCP 图像的优先级

您可以指定importance="high"来提高 LCP 或其他关键图像的优先级。

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

以下比较显示了 Google 航班页面,其中 LCP 背景图像加载有优先级提示和没有优先级提示两种。 将优先级设置为高,LCP 从 2.6s 提高到 1.9s.

video in gif

一项使用 Cloudflare 工作人员重写 Google 航班页面以使用优先级提示的实验

降低首屏图片的优先级

您可以使用该importance属性来降低可能不重要的首屏图像的优先级,例如在图像轮播中。

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

Oodle应用程序的早期实验中,我们使用它来降低加载时​​未出现的图像的优先级。它将加载时间减少了2 秒。

img

降低预加载资源的优先级

要阻止预加载的资源与其他关键资源竞争,您可以提供降低其优先级的提示。您可以将此技术用于图像、脚本和 CSS。

<!-- 为非关键性预加载脚本赋予低优先级 -->
<link rel="preload" as="script" href="critical-script.js">
<link rel="preload" href="/js/script.js" as="script" importance="low">

<!-- 不阻塞其他资源的前提下预加载CSS和首图-->
<link rel="preload" as="style" href="theme.css" importance="low" onload="this.rel=stylesheet">

重新排列脚本

使页面的某些部分具有交互性所需的脚本是必不可少的,但不应阻止其他资源。您可以将这些标记为具有高优先级的异步。

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

如果脚本依赖于特定的 DOM 状态,则它们不能被标记为异步。但是,如果它们在页面上较低,则可能会以较低的优先级下载它们,如图所示。

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

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

浏览器以高优先级执行fetch。如果您有多个可能同时触发的提取,您可以对更关键的数据提取使用高默认优先级,对不太关键的数据使用较低的优先级。

// 重要的验证数据 (默认为高优先级)
let authenticate = await fetch('/user');

// 不重要的内容数据 (建议设置为低优先级)
let suggestedContent = await fetch('/content/suggested', {importance: 'low'});

优先提示实施说明

如上所述,优先级提示可以提高特定用例中的性能。我们希望以原始试验为契机,更好地了解变更的实际影响。我们对质量反馈设定明确的期望至关重要。

  • 属性是一个提示而不是一个指令。浏览器会尽量尊重开发者的偏好。浏览器也有可能在发生冲突时根据需要应用其对资源优先级的偏好。

  • 优先提示不应与预加载混淆。它们都是不同的,因为:

    • 预加载是强制获取而不是提示。
    • 更容易观察和测量预加载的影响。

    优先级提示可以通过增加优先级的粒度来补充预加载。如果您已经在页面顶部为 LCP 图像指定了预加载,那么“高”优先级提示可能不会带来显著的收益。但是,如果预加载是在其他不太重要的资源之后,那么高优先级提示可以提高 LCP。如果关键图像是 CSS 背景图像,则应使用importance = "high"加载它。

  • 在更多资源争夺可用网络带宽的环境中,优先级带来的显着收益将更加相关。这适用于无法并行下载的 HTTP/1.x 连接或低带宽 HTTP/2 连接。优先排序可以解决这些情况下的瓶颈。

  • CDNs没有统一实现 HTTP/2 优先级。即使浏览器使用优先级提示传达了建议的优先级;CDN 可能不会按照所需的顺序重新排列资源的优先级。这使得优先提示的测试变得困难。优先级在浏览器内部和支持优先级的协议(HTTP/2 和 HTTP/3)中应用,因此即使仅用于独立于 CDN 或源支持的内部浏览器优先级,它仍然值得使用。

  • 可能无法在初始设计中引入优先级提示作为最佳实践。可以在开发周期后期积极应用。您可以在页面上查看分配给不同资源的优先级,如果它们不符合您的预期,您可以引入优先级提示以进一步优化。

在 Chrome 95 之后使用 Preload

优先提示功能可在 Chrome 73 到 76 中试用,但由于 Chrome 95 中修复的预加载的优先级问题而未发布。 在 Chrome 95 之前,通过发出的请求<link rel=preload>总是在预加载扫描器看到的其他请求之前启动,即使其他请求具有更高的优先级。

通过 Chrome 95 中的修复和优先级提示的增强,我们希望开发人员将开始使用预加载实现其预期目的 - to 预加载解析器未检测到的资源(字体、导入、背景 LCP 图像)。preload提示的位置将影响预加载资源的时间。使用预加载的一些关键点是:

  • 在 HTTP 标头中包含预加载将导致它跳到其他所有内容之前。
  • 通常,对于高于“中”优先级的任何内容,预加载将按照解析器到达它们的顺序加载 - 所以如果您在 HTML 的开头包含预加载,请小心。
  • 字体预加载可能在头部末端或正文开始时效果最佳。
  • 导入预加载(动态导入() 或模块预加载) 应该在需要导入的脚本标记之后完成 (因此实际脚本首先被加载/解析)。基本上,如果脚本标签加载的脚本会触发依赖项的加载,请确保 <link rel=preload> 依赖项位于父脚本标签之后, 否则依赖项可能会在主脚本之前加载。按照正确的顺序,可以在加载依赖项时解析/评估主脚本。
  • 图像预加载将具有低优先级(没有优先级提示)并且应相对于异步脚本和其他低优先级或最低优先级标签进行排序。

原始试验

优先提示功能将作为从 Chrome 96 到 99的原始试验版提供。版本 96 已经在Canary提供,供希望尽早试用的开发人员使用。您可以注册您的域进行试用,并将token包含在您要测试的页面head 中。

您还可以在 Chrome 中启用实验性 Web 平台功能标志来测试该功能。

img

使用试用

下面是一组图片和不同优先级加载的脚本文件的对比。请注意,图像和脚本的默认优先级在 Chrome 94 上应用。另一方面,在 Chrome 96 上测试时应用通过重要性属性设置的优先级。

以下是 HTML 文件中包含的相关标记。

<!-- 包含在<head>中的试用token -->
<meta http-equiv="origin-trial" content="{Replace with origin trial token}">

<!-- 脚本文件的低优先级 -->
<script src="script.js" importance="low"></script>

<!-- 改变图片的优先级 -->
<img src="Background.jpg" width="400" importance="low">
<img src="Sunset.jpg" width="400" importance="high">

<!-- 注意如果未明确指定,importance="auto"是基于规范的默认值 -->
<img src="Flower.jpg">

img

Chrome 94的优先级- 稳定版

img

Chrome 96的优先级 - 灰度版

总结

开发人员可能对预加载行为中的修复以及最近对 Core Web Vitals 和 LCP 的关注的优先提示感兴趣。他们现在有额外的方式来实现他们想要的加载顺序。我们希望更多的开发者注册试用并通过可用渠道报告他们的反馈。