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

发布时间:2022 年 12 月 2 日;上次更新时间:2026 年 10 月 29 日

Browser Support

  • Chrome: 109.
  • Edge: 109.
  • Firefox Technology Preview: supported.
  • Safari: behind a flag.

Source

Chrome 团队重新引入了对用户可能访问的未来网页进行完整预渲染的功能。

预渲染简史

过去,Chrome 支持 <link rel="prerender" href="/next-page"> 资源提示,但除了 Chrome 之外,它并未得到广泛支持,而且它不是一个非常具有表现力的 API。

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

Chrome 团队现已在 Chrome 中重新引入了完整预渲染功能。为避免与现有用法发生冲突,并为未来扩展预渲染功能留出空间,这种新的预渲染机制不会使用 <link rel="prerender"...> 语法,该语法仍用于 NoState 预提取,并计划在未来某个时间点停用。

如何预渲染网页?

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

  1. 当您在 Chrome 地址栏(也称为“多功能框”)中输入网址时,如果 Chrome 根据您之前的浏览记录确信您会访问该网页,则可能会自动为您预渲染该网页。
  2. 当您使用书签栏时,如果您将指针悬停在某个书签按钮上,Chrome 可能会自动为您预渲染相应网页。
  3. 当您在 Chrome 地址栏中输入搜索字词时,Chrome 可能会根据搜索引擎的指示自动预渲染搜索结果页。
  4. 网站可以使用 Speculation Rules API,以程序化方式告知 Chrome 需要预渲染哪些网页。这取代了 <link rel="prerender"...> 过去的功能,并允许网站根据网页上的推测规则主动预渲染网页。这些标记可以静态存在于网页上,也可以由 JavaScript 根据网页所有者的需要动态注入。

在上述每种情况下,预渲染的行为就像是在不可见的后台标签页中打开了网页,然后通过将前台标签页替换为该预渲染的网页来“激活”该网页。如果某个网页在完全预渲染之前被激活,则其当前状态为“前台”,并会继续加载,这意味着您仍然可以抢占先机。

由于预渲染的网页是在隐藏状态下打开的,因此许多会导致侵入式行为的 API(例如提示)在此状态下不会激活,而是会延迟到网页激活后才激活。在少数情况下,如果无法做到这一点,系统会取消预渲染。Chrome 团队正在努力将预渲染取消原因作为 API 公开,并增强开发者工具功能,以便更轻松地识别此类极端情况。

预渲染的影响

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

预渲染的影响示例。

示例网站已经是一个快速网站,但即使如此,您也可以看到预渲染如何改善用户体验。因此,这也会直接影响网站的 Core Web Vitals,使 LCP 接近于零,降低 CLS(因为任何加载 CLS 都会在初始视图之前发生),并提高 INP(因为加载应在用户互动之前完成)。

即使网页在完全加载之前就已激活,但由于网页加载已预先开始,因此加载体验应该会有所改善。如果在预渲染仍在进行时激活了链接,预渲染页面将移至主框架并继续加载。

不过,预渲染确实会占用额外的内存和网络带宽。请注意,不要过度预渲染,以免消耗用户资源。仅在网页极有可能被访问时才进行预渲染。

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

查看 Chrome 的地址栏联想查询

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

Chrome 联想查询页面,经过滤后,根据输入的文字显示低(灰色)、中(琥珀色)和高(绿色)联想查询。
Chrome 预测器页面。

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

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

这些预测器还会驱动地址栏中的建议选项,您可能已经注意到了:

Chrome 地址栏“预输入”功能
地址栏“预输入”功能。

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

  • 如果置信度大于 30%(显示为琥珀色),Chrome 会主动预连接到该网域,但不会预渲染该网页。
  • 如果置信度高于 50%(显示为绿色),Chrome 将预渲染该网址。

Speculation Rules API

对于 Speculation Rules API 预渲染选项,Web 开发者可以在其网页中插入 JSON 指令,以告知浏览器要预渲染哪些网址。

网址列表

推测规则可以基于网址列表:

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

文档规则

推测规则也可以是使用 where 语法的“文档规则”。这会根据 href 选择器(基于 网址格式 API)或 CSS 选择器推测文档中找到的链接:

<script type="speculationrules">
{
  "prerender": [{
    "where": {
      "and": [
        { "href_matches": "/*" },
        { "not": {"href_matches": "/wp-admin"}},
        { "not": {"href_matches": "/*\\?*(^|&)add-to-cart=*"}},
        { "not": {"selector_matches": ".do-not-prerender"}},
        { "not": {"selector_matches": "[rel~=nofollow]"}}
      ]
    }
  }]
}
</script>

渴望

Browser Support

  • Chrome: 121.
  • Edge: 121.
  • Firefox Technology Preview: supported.
  • Safari: behind a flag.

Source

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

  • conservative:在发生指针点击或轻触时,该设置会执行推测。
  • moderate:在桌面设备上,当您将光标悬停在链接上达到 200 毫秒时(或者发生 pointerdown 事件时,以更快者为准;在移动设备上没有 hover 事件),该设置会执行推测。自 2025 年 8 月起,在移动设备上,我们改为根据复杂的视口启发法来确定。如果锚点位于距离上一次指针按下位置的垂直距离 30% 以内,且锚点大小至少是视口中最大锚点的 0.5 倍,则在用户停止滚动 500 毫秒后,会触发复杂的视口启发法。如本文档中所述。
  • eager:此预加载设置的行为过去与 immediate 相同,但从 Chrome 143 开始发生了变化。在桌面设备上,如果您将指针悬停在链接上 10 毫秒,系统就会执行推测。在移动设备上,我们从 2026 年 1 月开始改为基于简单的视口启发法来确定。锚点进入视口 50 毫秒后,会触发简单的视口启发法。
  • immediate:该设置用于尽快进行推测,即观察到推测规则后立即进行推测。

list 规则的默认 eagerness 为 immediate。eager、moderate 和 conservative 选项可用于将 list 规则限制为用户与之互动的特定网址列表。不过,在许多情况下,使用具有适当 where 条件的 document 规则可能更合适。

document 规则的默认 eagerness 为 conservative。由于一个文档可能包含多个网址,因此在 document 规则中使用 immediate 时应谨慎(另请参阅下文的 Chrome 限制部分)。

具体使用哪种 eagerness 设置取决于您的网站。对于轻量级静态网站,更积极地进行推测可能成本较低,并且对用户有益。对于架构更复杂、网页载荷更重的网站,可能更倾向于减少推测频率,直到获得更多来自用户的明确意图信号,从而减少浪费。

moderate 选项是一种折中方案,许多网站都可以从以下推测规则中受益:当指针悬停在链接上 200 毫秒或发生 pointerdown 事件时,系统会预渲染链接,这是一种基本但功能强大的推测规则实现:

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

预取

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

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

Prerender until script

Chrome 团队还在努力将 prerender_until_script 添加到 Speculation Rules API(请参阅实现 bug)。这将是预提取和预渲染之间的一个步骤,并以类似的方式使用:

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

与 NoState prefetch 类似,这会预提取 HTML 文档以及该 HTML 中可用的子资源。不过,它会更进一步,开始预渲染网页,并在遇到第一个脚本时停止。

这意味着,对于没有 JavaScript 或仅在页脚中包含 JavaScript 的网页,几乎可以提前完全预渲染。<head> 中包含脚本的网页无法预渲染,但仍会受益于子资源提取。

这样可以避免 JavaScript 执行产生意外副作用的风险,但与仅使用 prefetch 相比,性能提升幅度要大得多。

Chrome 限制

Chrome 设有相关限制,以防止过度使用 Speculation Rules API:

eagerness 预取 预渲染
immediate 50 10
eager/moderate(移动设备) 6 (FIFO) 2 (FIFO)
eager / moderate(桌面设备) 2 (FIFO) 2 (FIFO)
conservative 2 (FIFO) 2 (FIFO)
Chrome 中的推测限制。

eager、moderate 和 conservative 设置(取决于用户互动)以先进先出 (FIFO) 方式运行:达到限制后,新的推测会导致最旧的推测被取消并替换为较新的推测,以节省内存。

已取消的推测可以再次触发(例如,再次将鼠标悬停在该链接上),这将导致该网址被重新推测,从而挤出最旧的推测。在这种情况下,之前的推测会将该网址的所有可缓存资源缓存到 HTTP 缓存中,因此再次推测应该会降低费用。因此,默认情况下,该限制设置为适中的阈值 2。在移动设备上,我们使用更高的阈值 6 进行预提取,因为移动设备上没有“悬停”操作,替代的移动设备视口启发式算法不太准确,并且预提取的开销低于预渲染(在移动设备上,我们仍将预渲染的限制设为 2)。

静态列表规则不会由用户操作触发,因此具有更高的限制,因为浏览器无法知道需要哪些规则以及何时需要这些规则。

鉴于这是一种不太精确的启发法,Chrome 还考虑在移动设备上将 eager 和 moderate 的限制提高到 5,至少对于预提取是这样。使用 eager 的开发者可能需要考虑在视口中提供多个链接时,额外使用 conservative 规则,以便即使未被选为前两个链接之一,也能进行推测。

immediate 限制也是动态的,因此移除 list 网址脚本元素会取消这些已移除的推测,从而释放容量。

Chrome 还会阻止在某些情况下使用推测,包括:

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

在激活之前,Chrome 也不会在预渲染的网页上渲染跨域 iframe。

所有这些条件都是为了减少过度推测在对用户不利时产生的影响。

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

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

  • 静态包含的推测规则:例如,如果新闻媒体网站或博客经常是大部分用户的下一个导航目标,则可以预渲染最新文章。或者,可以使用包含 moderate 或 conservative 的文档规则在用户与链接互动时进行推测。
  • 动态插入的推测规则:这可能基于应用逻辑、针对用户进行个性化设置,或基于其他启发法。

如果您倾向于根据悬停或点击链接等操作进行动态插入(就像过去许多库使用 <link rel=prefetch> 所做的那样),建议您查看文档规则,因为这些规则可让浏览器处理您的许多用例。

推测规则可以添加到主框架的 <head> 或 <body> 中。子框架中的推测规则不会执行,预渲染页面中的推测规则只有在页面激活后才会执行。

Speculation-Rules HTTP 标头

Browser Support

  • Chrome: 121.
  • Edge: 121.
  • Firefox: not supported.
  • Safari: behind a flag.

Source

推测规则也可以通过使用 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 文件的网址。如果您需要选择部分或全部同源链接,此功能可能特别有用。

推测规则标记字段

Browser Support

  • Chrome: 136.
  • Edge: 136.
  • Firefox: not supported.
  • Safari: behind a flag.

Source

您还可以在推测规则 JSON 语法中,在总体级别为规则集中的所有推测规则添加“标记”:

{
  "tag": "my-rules",
  "prefetch": [{
      "urls": ["next.html"]
  }],
  "prerender": [{
      "urls": ["next2.html"]
  }]
}

或者在单个规则级别:

{
  "prefetch": [{
    "tag": "my-prefetch-rules",
    "urls": ["next.html"]
  }],
  "prerender": [{
    "tag": "my-prerender-rules",
    "urls": ["next2.html"]
  }]
}

然后,此标记会反映在 Sec-Speculation-Tags HTTP 标头中,该标头可用于在服务器端过滤推测规则。如果推测涵盖多条规则,Sec-Speculation-Tags HTTP 标头可以包含多个标记,如以下示例所示:

Sec-Speculation-Tags: null
Sec-Speculation-Tags: null, "cdn-prefetch"
Sec-Speculation-Tags: "my-prefetch-rules"
Sec-Speculation-Tags: "my-prefetch-rules", "my-rules", "cdn-prefetch"

有些 CDN 会自动注入推测规则,但会阻止对非边缘缓存网页进行推测,以避免此功能导致源服务器用量增加。通过标记,他们可以识别由其默认规则集发起的推测,但仍允许网站添加的任何规则传递到源站。

规则集标记也会显示在 Chrome 开发者工具中。

推测规则 target_hint 字段

Browser Support

  • Chrome: 138.
  • Edge: 138.
  • Firefox: not supported.
  • Safari: not supported.

Source

推测规则还可以包含 target_hint 字段,其中包含有效的浏览上下文名称或关键字,用于指示网页希望在何处激活预渲染的内容:

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

此提示允许处理 target="_blank" 链接的预渲染推测:

<a target="_blank" href="next.html">Open this link in a new tab</a>

目前,Chrome 仅支持 "target_hint": "_blank" 和 "target_hint": "_self"(如果未指定,则为默认值),并且仅支持预渲染,不支持预提取。

只有 urls 推测规则需要 target_hint,因为对于文档规则,target 是从链接本身获知的。

推测规则和单页应用

推测规则仅支持由浏览器管理的完整网页导航,不支持单页应用 (SPA) 或应用 shell 网页。这些架构不使用文档提取,而是对数据或页面进行 API 提取或部分提取,然后在当前页面中进行处理和呈现。这些所谓的“软导航”所需的数据可以由应用在推测规则之外预提取,但无法预渲染。

Speculation Rules 可用于从上一页预渲染应用本身。这有助于抵消某些 SPA 产生的部分额外初始加载费用。不过,应用内的路由更改无法预渲染。

调试推测规则

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

多条推测规则

您还可以向同一网页添加多条推测规则,这些规则会附加到现有规则中。因此,以下不同方式都会导致 one.html 和 two.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>

Browser Support

  • Chrome: 141.
  • Edge: 141.
  • Firefox: 154.
  • Safari: not supported.

Source

在预提取或预渲染网页时,某些网址参数(技术上称为搜索参数)可能对服务器实际传送的网页并不重要,而仅供客户端 JavaScript 使用。

例如,Google Analytics 会使用 UTM 参数来衡量广告系列效果,但这些参数通常不会导致服务器提供不同的网页。这意味着,page1.html?utm_content=123 和 page1.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 123 和 124 的 /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 标头,并等待预提取完成。

您还可以向 expects_no_vary_search 添加多个参数,并用空格分隔(因为 No-Vary-Search 是 HTTP 结构化标头):

    "expects_no_vary_search": "params=(\"param1\" \"param2\" \"param3\")"

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

推测规则仅限于在同一标签页中打开的网页,但我们正在努力减少这一限制。

默认情况下,预渲染仅限于同源网页。可以启用预渲染同网站跨域网页(例如,https://a.example.com 可以预渲染 https://b.example.com 上的网页)。如需使用此功能,推测的网页(在本例中为 https://b.example.com)需要通过添加 Supports-Loading-Mode: credentialed-prerender HTTP 标头来选择启用,否则 Chrome 将取消推测。

未来版本可能还会允许预渲染非同站、跨域网页,前提是预渲染的网页不存在 Cookie,并且预渲染的网页通过类似的 Supports-Loading-Mode: uncredentialed-prerender HTTP 标头选择启用。

推测规则已经支持跨域预提取,对于同网站、跨域预提取,没有任何限制。仅当跨域网域的 Cookie 不存在时,才支持不同网站、跨域预提取。如果用户之前访问过该网站并留下了 Cookie,则系统不会使用推测规则,并且会在开发者工具中显示失败。

鉴于这些当前限制,有一种模式可以改善用户在内部链接和外部链接(如果可能)方面的体验,即预渲染同源网址并尝试预提取跨域网址:

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

为了确保安全性,默认情况下必须限制对跨域链接进行跨域推测。对于跨域目标,它比 <link rel="prefetch"> 有所改进,后者也不会发送 Cookie,但仍会尝试预提取,这会导致预提取被浪费,需要重新发送,或者更糟糕的是,加载错误的网页。

检测 Speculation Rules 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 预渲染演示。

出于安全原因,使用 innerHTML 将 <script type = "speculationrules"> 元素直接插入 DOM 不会注册推测规则,必须按照前面所示的方式添加。不过,如果使用 innerHTML 动态插入的内容包含新链接,则这些链接会被网页上的现有规则捕获。

同样,直接在 Chrome 开发者工具中修改 Elements 面板以添加 <script type = "speculationrules"> 元素不会注册推测规则,而是必须从控制台运行脚本以动态地将此元素添加到 DOM 中,从而插入规则。

通过跟踪代码管理器添加推测规则

如需使用 Google 跟踪代码管理器 (GTM) 等代码管理器添加推测规则,需要通过 JavaScript 插入这些规则,而不是直接通过 GTM 添加 <script type = "speculationrules"> 元素,原因与前面提到的相同:

Google 跟踪代码管理器中的自定义 HTML 代码配置
通过 Google 跟踪代码管理器添加推测规则。

请注意,此示例使用 var,因为 GTM 不支持 const。

取消推测规则

移除推测规则会导致预渲染被取消。不过,当这种情况发生时,可能已经消耗了资源来启动预渲染,因此,如果有可能需要取消预渲染,建议不要进行预渲染。另一方面,缓存的资源仍然可以重复使用,因此取消操作可能不会完全浪费,并且可能仍有利于未来的推测和导航。

Browser Support

  • Chrome: 138.
  • Edge: 138.
  • Firefox: not supported.
  • Safari: not supported.

Source

您还可以使用 Clear-Site-Data HTTP 标头以及 prefetchCache 和 prerenderCache 指令来取消推测。

当服务器上的状态发生变化时,此功能非常有用。例如,在调用“添加到购物车”API 或登录/退出登录 API 时。

理想情况下,这些状态更新应使用 Broadcast Channel API 等 API 传播到预渲染的网页,但如果无法做到这一点,或者在实现此类逻辑之前,取消推测可能会更容易。

推测规则和内容安全政策

由于推测规则使用 <script> 元素,因此即使它们仅包含 JSON,也需要包含在 script-src Content-Security-Policy 中(如果网站使用此政策,则使用哈希或 Nonce)。

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

检测并停用预渲染

预渲染通常能为用户带来良好的体验,因为它可以快速(通常是即时)渲染网页。这既有利于用户,也有利于网站所有者,因为预渲染的网页可以提供更好的用户体验,而这在其他情况下可能很难实现。

不过,在某些情况下,您可能不希望预渲染网页,例如当网页状态发生变化时(无论是基于初始请求,还是基于网页上执行的 JavaScript)。

在 Chrome 中启用和停用预渲染

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

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

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

Sec-Purpose: prefetch;prerender

使用 Speculation Rules API 预提取的网页会将此标头设置为 prefetch:

Sec-Purpose: prefetch

服务器可以根据此标头做出响应,以记录推测请求、返回不同的内容或阻止预渲染。如果返回的最终响应代码不是成功代码(即重定向后不在 200-299 范围内),则系统不会预渲染该网页,并且会舍弃所有预提取的网页。另请注意,204 和 205 响应也不适用于预渲染,但适用于预提取。

如果您不希望预渲染特定网页,最好返回非 2XX 响应代码(例如 503),以确保不会发生这种情况。不过,为了提供最佳体验,建议您允许预渲染,但使用 JavaScript 延迟执行只有在实际查看网页时才应执行的操作。

在 JavaScript 中检测预渲染

在页面预渲染期间,document.prerendering API 将返回 true。网页可以使用此 API 在预渲染期间阻止或延迟某些活动,直到网页实际激活。

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

您可以编写一个函数来检查预渲染和预渲染页面,如下所示:

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

要查看网页是否已预渲染(完全或部分),最简单的方法是在网页激活后打开开发者工具,然后在控制台中输入 performance.getEntriesByType('navigation')[0].activationStart。如果返回非零值,则表示页面已预渲染:

Chrome 开发者工具中的控制台,其中显示了正数 activationStart,表示网页已预渲染
在控制台中测试预渲染。

当用户查看网页而激活该网页时,系统会在 document 上分派 prerenderingchange 事件,然后该事件可用于启用之前默认在网页加载时启动但您希望延迟到用户实际查看网页时启动的活动。

借助这些 API,前端 JavaScript 可以检测预渲染的网页并采取适当的操作。

对分析的影响

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

只有在用户极有可能加载网页时,才应预渲染网页。这就是为什么只有在概率很高(超过 80% 的时间)时,Chrome 地址栏预渲染选项才会生效。

不过,预渲染的网页可能会对分析产生影响,尤其是在使用 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, {once: true});
  } else {
    resolve();
  }
});

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

initAnalytics();

另一种方法是,将分析活动延迟到页面首次可见时,这样既能涵盖预渲染的情况,也能涵盖在后台打开标签页的情况(例如,右键点击并在新标签页中打开):

// Set up a promise for when the page is first made visible
const whenFirstVisible = new Promise((resolve) => {
  if (document.hidden) {
    document.addEventListener('visibilitychange', resolve, {once: true});
  } else {
    resolve();
  }
});

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

initAnalytics();

虽然这可能适用于分析和类似用例,但在其他情况下,您可能希望为这些情况加载更多内容,因此可能需要使用 document.prerendering 和 prerenderingchange 来专门定位预渲染页面。

在预渲染期间不加载其他内容

在预渲染阶段,可以使用前面讨论过的相同 API 来阻止其他内容。这些可以是您不希望在预渲染阶段运行的特定 JavaScript 部分或整个脚本元素。

例如,假设有以下脚本:

<script src="https://example.com/app/script.js" async></script>

您可以将其更改为动态插入的脚本元素,该元素仅根据之前的 whenActivated 函数进行插入:

async function addScript(scriptUrl) {
  await whenActivated;
  const script = document.createElement('script');
  script.src = 'scriptUrl';
  document.body.appendChild(script);
}

addScript('https://example.com/app/script.js');

这有助于保留包含分析功能的独特脚本,或根据状态或访问期间可能发生变化的其他变量来呈现内容。例如,推荐内容、登录状态或购物车图标都可能被保留,以确保呈现最新信息。

虽然在使用预渲染时,这种情况可能更常发生,但对于在前面提到的后台标签页中加载的网页,这些条件也同样适用(因此可以使用 whenFirstVisible 函数代替 whenActivated)。

在许多情况下,理想的做法是在常规 visibilitychange 更改时也检查状态。例如,当用户返回到已进入后台的页面时,任何购物车计数器都应更新为购物车中的最新商品数量。因此,这并非预渲染特有的问题,预渲染只是让现有问题变得更加明显。

Chrome 缓解了手动封装脚本或函数的部分需求,其中一种方式是如前所述,保留某些 API,并且不呈现第三方 iframe,因此只需手动保留其上的内容。

衡量效果

在衡量效果指标时,分析工具应考虑是根据激活时间还是根据浏览器 API 报告的网页加载时间来衡量这些指标。

对于 Core Web Vitals,Chrome 通过 Chrome 用户体验报告进行衡量,旨在衡量用户体验。因此,这些指标是根据激活时间来衡量的。例如,这通常会使 LCP 降至 0 秒,表明这是提升 Core Web Vitals 的绝佳方式。

从 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 Jodoin 提供,来源:Unsplash