在 Chrome 中预渲染网页以实现即时网页导航

浏览器支持

  • 109
  • 109
  • x
  • x

Chrome 团队一直在努力研究各种选项,以便针对用户未来可能会浏览的网页恢复完整的预呈现功能。

预渲染简史

过去,Chrome 支持 <link rel="prerender" href="/next-page"> 资源提示,但它并未得到除 Chrome 之外的广泛支持,也并非极具表现力的 API。

这种使用链接 rel=prerender 提示的旧版预渲染已被弃用,取而代之的是 NoState Prefetch,后者会提取未来页面所需的资源,但不会完全预渲染页面,也不会执行 JavaScript。NoState 预提取确实能通过提升资源加载速度来帮助提高网页性能,但不会像完全预渲染那样提供即时网页加载

Chrome 团队现已在 Chrome 中重新引入完整的预渲染。为避免现有使用方面的复杂性以及预渲染的未来扩展,这种新的预渲染机制不会使用 <link rel="prerender"...> 语法,该语法仍然适用于 NoState 预提取,并且计划在未来某个时间点停用该语法。

如何预呈现网页?

可以通过以下四种方式预渲染页面,所有这些方式都旨在加快导航速度:

  1. 当您在 Chrome 地址栏(也称为“多功能框”)中输入网址时,Chrome 可能会自动为您预呈现相应网页(如果系统非常肯定您会访问该网页)。
  2. 当您在 Chrome 地址栏中输入搜索字词时,Chrome 可能会按照搜索引擎的指示自动预呈现搜索结果页。
  3. 网站可以使用 Speculation Rules API,以编程方式告知 Chrome 要预呈现哪些网页。这将替换 <link rel="prerender"...> 的做法,并允许网站根据网页上的推测规则主动预呈现网页。这些元素可以静态存在于网页上,也可以由 JavaScript 按照网页所有者认为合适的方式动态注入。

无论是哪种情况,预渲染都假定网页是在一个不可见的后台标签页中打开的,然后通过将前台标签页替换为预渲染的网页来“激活”。如果网页在完全预渲染之前就已激活,那么其当前状态为“前台”并会继续加载,这意味着您仍可以获得良好的开端。

由于预渲染的网页是在隐藏状态下打开的,因此一些会造成干扰行为的 API(例如,提示)不会在此状态下激活,而是会延迟到该网页被激活为止。在少数情况下,如果还不能这样,预渲染会被取消。Chrome 团队正努力将预渲染取消原因作为 API 提供,同时增强开发者工具功能,以便更轻松地识别此类极端情况。

预渲染的影响

预渲染可实现近乎即时的网页加载,如以下视频所示:

预渲染的影响示例。

示例网站已经可以提升速度,但即便如此,您也可以看出预渲染如何改善用户体验。因此,这还会对网站的核心网页指标产生直接影响,因为 LCP 接近于零,CLS 降低(因为任何加载 CLS 都发生在初始查看之前),并且 INP(因为加载应在用户互动之前完成)会有所提升。

即使网页在完全加载之前激活,在网页加载前先启动,也应该能改善加载体验。如果在预渲染仍在进行的情况下激活了链接,预渲染页面将移至主框架并继续加载。

不过,预渲染确实会占用额外的内存和网络带宽。注意不要过度预渲染,以用户资源为代价。仅在系统非常有可能转到某个网页时进行预渲染。

如需详细了解如何在数据分析中衡量实际性能影响,请参阅衡量性能部分。

查看 Chrome 地址栏中的联想查询

对于第一个用例,您可以在 chrome://predictors 页面中查看 Chrome 对网址的预测结果:

Chrome 预测者页面的屏幕截图,根据输入的文本进行了过滤,以显示低(灰色)、中(琥珀色)和高(绿色)预测。
Chrome 预测器页面。

绿线表示触发预渲染的置信度足够高。在此示例中,输入“s”可以提供合理的置信度(琥珀色),但一旦您输入“sh”,Chrome 就会确信您几乎总是导航到 https://sheets.google.com

此屏幕截图是在相对较新的 Chrome 安装中截取的,并且过滤掉了零置信度预测,但如果您查看自己的预测程序,则可能会看到明显更多的条目,并且可能需要更多字符,才能达到足够高的置信度。

这些预测器也是促使地址栏建议的选项的原因:

地址栏“提前输入”功能的屏幕截图
地址栏的“提前输入”功能。

Chrome 会根据您输入的内容和选择不断更新预测器。

  • 如果置信度高于 50%(显示为黄色),Chrome 就会主动预连接该网域,但不会预呈现该网页。
  • 如果置信度高于 80%(显示为绿色),Chrome 就会预呈现相应网址。

Speculation Rules API

对于第三种预渲染选项,Web 开发者可以在其页面上插入 JSON 指令,以告知浏览器要预渲染的网址:

<script type="speculationrules">
{
  "prerender": [
    {
      "urls": ["next.html", "next2.html"]
    }
  ]
}
</script>

或者通过文档规则(适用于 Chrome 121),这些规则会根据 href 或 CSS 选择器预呈现在文档中找到的链接:

<script type="speculationrules">
{
  "prerender": [{
    "where": {
      "and": [
        { "href_matches": "/*" },
        { "not": {"selector_matches": ".do-not-prerender"}},
        { "not": {"selector_matches": "[rel=nofollow]"}}
      ]
    }
  }]
}
</script>

急切度

浏览器支持

  • 121
  • 121
  • x
  • x

eagerness 设置用于指示推测应何时触发,这对文档规则特别有用:

  • immediate:用于尽快(即在观察到推测规则后)进行推测。
  • eager:其行为与 immediate 设置相同,但未来,我们会考虑将其放置在 immediatemoderate 之间的某个位置。
  • moderate:如果将鼠标指针悬停在链接上 200 毫秒(或 pointerdown 事件,如果时间较短,并且在移动设备上没有 hover 事件,则会发生推测)。
  • conservative:用于推测指针或触摸事件。

list 规则的默认 eagernessimmediatemoderateconservative 选项可用于将 list 规则限制在用户与特定列表互动的网址上。不过,在许多情况下,具有适当 where 条件的 document 规则可能更合适。

document 规则的默认 eagernessconservative。由于一个文档可以包含多个网址,因此应谨慎使用 immediateeager 作为 document 规则(另请参阅下面的 Chrome 限制部分)。

使用哪种 eagerness 设置取决于您的网站。对于轻量级的静态网站,更积极进行推测可能产生的费用很低,而且对用户有益。架构更复杂且网页载荷较重的网站可能倾向于降低推测频率,直至用户收到更积极的信号来限制资源浪费为止,从而减少浪费。

moderate 选项是一种中间方法,许多网站都可以受益于以下推测规则,该规则会在用户悬停鼠标或按下指针时将所有链接预呈现为推测规则的基本实现,但又非常强大:

<script type="speculationrules">
{
  "prerender": [{
    "where": {
      "href_matches": "/*"
    },
    "eagerness": "moderate"
  }]
}
</script>

预取

推测规则还可用于仅预提取网页,而不进行完整的预渲染。这通常是预渲染的第一步:

<script type="speculationrules">
{
  "prefetch": [
    {
      "urls": ["next.html", "next2.html"]
    }
  ]
}
</script>

Chrome 限制

Chrome 设置了一些限制,以防止过度使用 Speculation Rules API:

渴望 预取 预渲染
immediate/eager 50 10
moderate/conservative 2(先进先出) 2(先进先出)
Chrome 中的推测限制。

moderateconservative 设置取决于用户互动,采用先进先出 (FIFO) 方式工作:达到限制后,新的推测会导致最旧的推测被取消,并将其替换为新的推测,以节省内存。已取消的推测可能会再次触发(例如,再次将鼠标悬停在该链接上时),这会导致系统重新推测相应网址,从而推出最早的推测。在这种情况下,之前的推测会在相应网址的 HTTP 缓存中缓存任何可缓存的资源,因此如果再猜测一段时间,成本应该会降低。正因如此,该限值设为一般阈值 2。静态列表规则不是由用户操作触发的,因此具有更高的限制,因为浏览器无法知道哪些规则以及何时需要它们。

immediateeager 限制也是动态的,因此移除 list 网址脚本元素将通过取消这些已移除的推测来增加容量。

Chrome 还将防止在特定情况下使用推测,包括:

  • Save-Data
  • 节能模式(启用后以及电量不足时)。
  • 内存限制。
  • “预加载网页”设置处于关闭状态(此设置也会被 uBlock Origin 等 Chrome 扩展程序明确关闭)。
  • 已在后台标签页中打开页面。

此外,在激活之前,Chrome 也不会在预渲染的网页上呈现跨源 iframe。

所有这些条件都是在过度推测对用户无害时,旨在减少过度推测带来的影响。

如何在网页上添加推测规则

推测规则可以静态包含在网页的 HTML 中,也可以通过 JavaScript 动态插入网页:

  • 静态包含的推测规则:例如,新闻媒体网站或博客可能会预呈现最新文章(如果大多数用户的下一个导航操作经常会用到),或者,使用具有 moderateconservative 的文档规则可用于推测用户与链接互动的情况。
  • 动态插入的推测规则:可以基于应用逻辑、针对用户进行个性化设置或基于其他启发词语。

如许多过去使用 <link rel=prefetch> 的库一样,支持基于操作(例如将鼠标悬停在链接上或点击链接)进行动态插入,建议您查看文档规则,因为这些规则可让浏览器处理您的许多用例。

您可以在主框架的 <head><body> 中添加推测规则。子框架中的推测规则不会起作用,并且仅当激活预渲染的网页之后,才会对预渲染网页中的推测规则起作用。

Speculation-Rules HTTP 标头

浏览器支持

  • 121
  • 121
  • x
  • x

来源

您也可以使用 Speculation-Rules HTTP 标头(而不是直接将其添加到文档的 HTML 中)来提供推测规则。这样可以更轻松地通过 CDN 进行部署,而无需更改文档内容本身。

Speculation-Rules HTTP 标头随文档一起返回,并指向包含推测规则的 JSON 文件的位置:

Speculation-Rules: "/speculationrules.json"

此资源必须使用正确的 MIME 类型;如果是跨源资源,则通过 CORS 检查。

Content-Type: application/speculationrules+json
Access-Control-Allow-Origin: *

如果要使用相对网址,您可能需要在推测规则中添加 "relative_to": "document" 键。否则,相对网址将相对于推测规则 JSON 文件的网址。如果您需要选择部分(或所有)同源链接,此方法可能特别有用。

推测规则和 SPA

推测规则仅适用于由浏览器管理的整页导航,不适用于单页应用 (SPA) 或应用 Shell 页面。这些架构不使用文档提取,而是通过 API 或部分提取数据或页面来提取数据或页面,提取数据或页面,然后处理并呈现在当前页面中。应用可在推测规则之外预提取这些所谓的“软导航”所需的数据,但无法预渲染这些数据。

推测规则可用于从上一页预呈现应用本身。这有助于抵消一些 SPA 产生的额外初始加载费用。但是,无法预渲染应用内的路由更改。

调试推测规则

如需了解有助于查看和调试这个新 API 的 Chrome 开发者工具新功能,请参阅有关调试推测规则的专用博文

多条推测规则

您也可以向同一网页添加多个推测规则,并将这些规则附加到现有规则。因此,以下不同方式都会同时导致 one.htmltwo.html 预渲染:

网址列表

<script type="speculationrules">
{
  "prerender": [
    {
      "urls": ["one.html", "two.html"]
    }
  ]
}
</script>

多个 speculationrules

<script type="speculationrules">
{
  "prerender": [
    {
      "urls": ["one.html"]
    }
  ]
}
</script>
<script type="speculationrules">
{
  "prerender": [
    {
      "urls": ["two.html"]
    }
  ]
}
</script>

一组 speculationrules 中有多个列表

<script type="speculationrules">
{
  "prerender": [
    {
      "urls": ["one.html"]
    },
    {
      "urls": ["two.html"]
    }
  ]
}
</script>

浏览器支持

  • 121
  • 121
  • x
  • x

来源

预提取或预呈现网页时,某些网址参数(技术上称为“搜索参数”)可能对服务器实际提供的网页不重要,只能由客户端 JavaScript 使用。

例如,Google Analytics(分析)虽然使用 UTM 参数来衡量广告系列,但通常不会从服务器传送不同的网页,这意味着,page1.html?utm_content=123page1.html?utm_content=456 将从服务器传送同一页面,以便从缓存中重复使用同一页面。

同样,应用也可以使用其他仅在客户端处理的网址参数。

No-Vary-Search 提案允许服务器指定参数,此类参数不会导致所传递的资源出现差异,从而允许浏览器重复使用之前缓存的文档版本,而该版本仅在这些参数上存在差异。Chrome(以及基于 Chromium 的浏览器)支持此功能(仅适用于预提取导航推测)。

推测规则支持使用 expects_no_vary_search 来指明 No-Vary-Search HTTP 标头预计返回的位置。这样做有助于进一步避免不必要的下载。

<script type="speculationrules">
{
  "prefetch": [{
    "urls": ["/products*"],
    "expects_no_vary_search": "params=(\"id\")"
  }]
}
</script>

<a href="/products?id=123">Product 123</a>
<a href="/products?id=124">Product 124</a>

在此示例中,产品 ID 123124/products 初始网页 HTML 是相同的。不过,如果客户端使用 JavaScript 通过 id 搜索参数提取商品数据,网页内容最终会有所不同。因此,我们会快速预提取该网址,并且该网址应返回一个 No-Vary-Search HTTP 标头,以表明该网页可用于任何 id 搜索参数。

但是,如果用户在预提取完成之前点击任意链接,则浏览器可能尚未收到 /products 网页。在这种情况下,浏览器不知道其中是否包含 No-Vary-Search HTTP 标头。然后,浏览器可以选择是再次提取链接,还是等待预提取完成,以查看其是否包含 No-Vary-Search HTTP 标头。expects_no_vary_search 设置可让浏览器知道页面响应应包含 No-Vary-Search HTTP 标头,并等待该预提取完成。

推测规则限制和未来增强功能

推测规则仅限于在同一标签页中打开的网页,但我们正在努力减少这种限制。默认情况下,预渲染仅限于同源网页。

预渲染同网站跨源网页(例如,https://a.example.com 可以在 https://b.example.com 上预渲染网页)。要使用预渲染的网页(在此示例中为 https://b.example.com),需要选择加入 Supports-Loading-Mode: credentialed-prerender HTTP 标头,否则 Chrome 将会取消预渲染。

未来版本还可以允许对跨源网页进行预渲染(其中网站选择启用类似的 Supports-Loading-Mode: uncredentialed-prerender HTTP 标头),并在新标签页中启用预渲染

检测推测规则 API 支持

您可以通过标准 HTML 检查功能检测 Speculation Rules API:

if (HTMLScriptElement.supports && HTMLScriptElement.supports('speculationrules')) {
  console.log('Your browser supports the Speculation Rules API.');
}

通过 JavaScript 动态添加推测规则

以下示例展示了如何使用 JavaScript 添加 prerender 推测规则:

if (HTMLScriptElement.supports &&
    HTMLScriptElement.supports('speculationrules')) {
  const specScript = document.createElement('script');
  specScript.type = 'speculationrules';
  specRules = {
    prerender: [
      {
        urls: ['/next.html'],
      },
    ],
  };
  specScript.textContent = JSON.stringify(specRules);
  console.log('added speculation rules to: next.html');
  document.body.append(specScript);
}

您可以在此预渲染演示页面上观看使用 JavaScript 插入的 Speculation Rules API 预渲染的演示。

取消推测规则

移除推测规则会导致预渲染被取消,但到预渲染之前,启动预渲染可能已花费资源,因此如果可能需要取消预渲染,建议不要进行预渲染。

推测规则和内容安全政策

由于推测规则使用 <script> 元素(即使它们仅包含 JSON),因此如果网站使用 JSON 格式(使用哈希值或 Nonce 格式),就必须将这些规则包含在 script-src 内容安全政策中。

可以将新的 inline-speculation-rules 添加到 script-src,从而支持从哈希或非 ced 脚本注入的 <script type="speculationrules"> 元素。这不支持初始 HTML 中包含的规则,因此,规则需要由 JavaScript 为使用严格 CSP 的网站注入。

检测和停用预渲染

预渲染通常会为用户提供良好的体验,因为它可以实现快速的网页渲染(通常是即时)。这对用户和网站所有者都有好处,因为预渲染的网页可以提供更好的用户体验,而这无疑是很难实现的。

不过,在某些情况下,您可能不想预渲染页面,例如页面更改状态时(基于初始请求或基于页面上执行的 JavaScript)。

在 Chrome 中启用和停用预渲染

只有那些已在 chrome://settings/performance/ 中通过“预加载网页”设置的 Chrome 用户才会启用预渲染功能。此外,在内存较小的设备上,或者操作系统处于“省流量”或“节能”模式时,系统也会停用预渲染功能。请参阅 Chrome 限制部分。

检测和停用服务器端预渲染

预渲染的网页将使用 Sec-Purpose HTTP 标头发送:

Sec-Purpose: prefetch;prerender

对于使用 Speculation Rules API 预提取的页面,系统会将此标头仅设置为 prefetch

Sec-Purpose: prefetch

服务器可以根据此标头进行响应,以记录推测请求、返回不同的内容或阻止发生预渲染。如果返回不成功响应代码(即,不是 200 或 304),则系统不会预呈现相应网页,并舍弃任何预提取网页。

如果您不希望预呈现特定网页,这是避免这种情况的最佳方式。不过,为了提供最佳体验,建议您改为允许预渲染,但要使用 JavaScript 延迟执行只有在用户实际查看网页之后才应执行的操作。

检测 JavaScript 中的预渲染

在网页进行预渲染时,document.prerendering API 会返回 true。网页可以使用此属性在预渲染期间防止(或延迟)某些活动,直到网页实际激活。

激活预渲染文档后,PerformanceNavigationTimingactivationStart 也将设置为非零时间,表示从预渲染开始到实际激活文档之间的时间。

您可以使用一个函数来检查预渲染网页和预渲染网页,如下所示:

function pagePrerendered() {
  return (
    document.prerendering ||
    self.performance?.getEntriesByType?.('navigation')[0]?.activationStart > 0
  );
}

要了解网页是否已预渲染,最简单的方法是在预渲染完成后打开开发者工具,然后在控制台中输入 performance.getEntriesByType('navigation')[0].activationStart。如果返回非零值,就表示该网页是预渲染的:

Chrome 开发者工具中的控制台,显示一条激活正值,表明网页已预渲染
在控制台中测试预渲染。

当浏览网页的用户激活该网页时,prerenderingchange 事件将在 document 上分派,然后可用于启用之前默认在网页加载时启动、但您希望延迟到用户实际浏览到该网页之前的 activity。

利用这些 API,前端 JavaScript 可以适当地检测预渲染的网页并采取相应措施。

对分析的影响

Google Analytics(分析)用于衡量网站使用情况,例如使用 Google Analytics(分析)衡量网页浏览量和事件数。或者,使用真实用户监控 (RUM) 衡量网页的性能指标。

仅当用户很有可能加载网页时,才应预渲染网页。因此,Chrome 地址栏预呈现选项仅在出现这种概率很高(超过 80% 的情况下)时才会出现。

但是,尤其是在使用 Speculation Rules API 时,预渲染的网页可能会对分析产生影响,并且网站所有者可能需要添加额外的代码,以便仅在启用时为预渲染的网页启用分析,因为并非所有分析服务提供商都默认执行此操作。

这可以通过使用 Promise 来实现,如果文档正在预渲染,它会等待 prerenderingchange 事件;如果现在,则立即解析:

// Set up a promise for when the page is activated,
// which is needed for prerendered pages.
const whenActivated = new Promise((resolve) => {
  if (document.prerendering) {
    document.addEventListener('prerenderingchange', resolve);
  } else {
    resolve();
  }
});

async function initAnalytics() {
  await whenActivated;
  // Initialise your analytics
}

initAnalytics();

衡量性能

为衡量性能指标,Google Analytics(分析)应考虑根据启用时间(而非浏览器 API 所报告的网页加载时间)来衡量性能指标是否更好。

对于核心网页指标,Chrome 通过 Chrome 用户体验报告进行衡量,旨在衡量用户体验。因此,这些指标是根据激活时间来衡量的。例如,这通常会导致 LCP 为 0 秒,这表明这是改进核心网页指标的绝佳方式。

从 3.1.0 版开始,web-vitals进行了更新,现采用与 Chrome 衡量 Core Web Vitals 的方式相同的方式处理预渲染的导航。此版本还会在 Metric.navigationType 属性中为这些指标标记预渲染导航。

衡量预渲染

通过 PerformanceNavigationTiming 的非零 activationStart 条目,可以看到网页是否为预渲染的网页。然后,您可以使用自定义维度来记录此事件,或在记录网页浏览量时进行类似记录,例如使用之前介绍的 pagePrerendered 函数

// Set Custom Dimension for Prerender status
gtag('set', { 'dimension1': pagePrerendered() });
// Initialise GA - including sending page view by default
gtag('config', 'G-12345678-1');

这样,您的分析报告就可以显示与其他类型的导航相比,预渲染了多少次导航,并且您可以将所有效果指标或业务指标与这些不同导航类型相关联。加快网页加载速度意味着用户满意度更高,这通常能对业务指标产生切实的影响,正如我们的案例研究所示。

在衡量为即时导航进行预呈现页面的业务影响时,您可以决定是否需要投入更多精力来使用此技术来允许更多导航项进行预渲染,或者调查未预呈现网页的原因。

衡量命中率

除了衡量预呈现后所访问网页的影响之外,衡量预呈现网页后但随后不会访问的网页也很重要。这可能意味着您过度预渲染,浪费了用户的宝贵资源,却收效甚微。

如需衡量这一点,您可以在插入推测规则后触发分析事件(在检查浏览器是否支持使用 HTMLScriptElement.supports('speculationrules') 进行预渲染之后),以表明已请求预渲染。(请注意,虽然已请求预渲染,但这并不表示预渲染已启动或完成,如前所述,预渲染只是对浏览器的一种提示,可以选择不根据用户设置、当前内存用量或其他启发法预渲染页面。)

然后,您可以将这些事件的数量与实际的预渲染网页浏览量进行比较。或者,您也可以在激活时触发另一个事件(如果这样更易于比较)。

然后,通过查看这两个数字之间的差异,即可估算“成功命中率”。对于您使用 Speculation Rules API 预呈现网页的网页,您可以适当调整规则,以确保保持较高的命中率,以便在用尽用户资源来帮助用户与不必要地使用资源之间保持平衡。

请注意,地址栏的预渲染可能不只是您的推测规则,导致某些预渲染的发生。如果您想区分,请查看 document.referrer(在地址栏导航(包括预渲染的地址栏导航)中,该元素将为空)。

另外,请务必查看没有预呈现的网页,因为这可能表示这些网页不符合预呈现的条件,即使是通过地址栏进行也是如此。这可能意味着您未从这项性能提升中受益。Chrome 团队希望添加额外的工具来测试预渲染资格(可能类似于 bfcache 测试工具),并且可能会添加一个 API 来公开预渲染失败的原因。

对扩展程序的影响

请参阅 Chrome 扩展程序:扩展 API 以支持即时导航的专门帖子,其中详细说明了扩展程序作者在预渲染网页时可能需要考虑的一些其他注意事项。

反馈

Chrome 团队正在积极开发预渲染功能,并且有许多计划扩大 Chrome 108 版本中的功能范围。欢迎大家针对 GitHub 代码库我们的问题跟踪器提供反馈,期待收到和分享这个激动人心的新 API 的案例研究。

致谢

缩略图,提供者:Marc-Olivier JodoinUnsplash 网站