跳转到内容

性能 · API

Speculation Rules API

发布于 更新于

Speculation Rules API 让页面在 <script type="speculationrules"> 内的 JSON 块或 Speculation-Rules 响应头中声明浏览器应在用户导航之前预取或完整预渲染哪些 URL,于是下一次点击直接由内存应答。对文档而言它取代了 <link rel="prefetch"> 以及已废弃的 <link rel="prerender">(Chrome 63 起后者变成 NoState Prefetch),而且在生产环境中仅 Chromium 支持。

<script type="speculationrules">
{
"prerender": [{ "where": { "href_matches": "/articles/*" }, "eagerness": "moderate" }],
"prefetch": [{ "urls": ["/next.html"] }]
}
</script>
Speculation-Rules: "/rules.json"

该块由浏览器解析而不执行;不支持该类型的引擎会忽略它。Chrome 109 随同源预渲染一起发布了该 API,Chrome 121 加入 Speculation-Rules 头并让 source 成员变为可选;Safari 26.2 在「SpeculationRules prefetch」偏好之后实现了 prefetch 规则,Firefox 没有实现(BCD html.elements.script.type.speculationrules)。

成员 类型 含义
prefetch、prerender 规则数组 动作。prefetch 下载响应;prerender 在隐藏标签页中加载并渲染页面,脚本也会执行。
urls 字符串数组 列表规则:显式 URL,相对文档解析(带 "relative_to": "document" 时相对规则集解析)。
where object 文档规则:对页面内链接的谓词,含 href_matches(URL 模式)、selector_matches(CSS 选择器)以及 and、or、not 组合子。
eagerness "immediate"、"eager"、"moderate"、"conservative" 何时执行。immediate 在解析时;moderate 在悬停 200 ms 之后(触摸设备上为 pointerdown);conservative 在 pointerdown;eager 在 Chrome 143 之前与 immediate 行为相同,之后改为基于视口的启发式。列表规则默认 immediate,文档规则默认 conservative。
requires array ["anonymous-client-ip-when-cross-origin"] 把跨源预取限定在私有预取代理上。
referrer_policy、tag、expects_no_vary_search、target_hint string 推测请求的 referrer、在 DevTools 和 Sec-Speculation-Tags 头中显示的标签、No-Vary-Search 提示,以及预渲染的目标(_self 或 _blank)。

Chrome 限制并发的推测:immediate 规则 10 个预渲染和 50 个预取,eager、moderate 与 conservative 规则各 2 个,出现更新的候选时按先进先出替换(Prerender pages in Chrome,developer.chrome.com)。预取请求带 Sec-Purpose: prefetch;预渲染的文档看到 document.prerendering === true,并在激活时收到 prerenderingchange 事件。

无。

Chromium 是唯一在生产环境中同时具备 prefetch 和 prerender 规则的引擎:Chrome 和 Edge 自 109 起,头形式自 121 起。Safari 26.2 只在启用「SpeculationRules prefetch」偏好时解析 prefetch 规则并忽略 prerender;Firefox 完全忽略该脚本类型(BCD html.elements.script.type.speculationrules)。不支持的引擎只是少了提前量,所以规则可以无条件发布。

示例覆盖一个规则集、预渲染页面需要的页面侧代码,以及兜底。

moderate 热度的文档规则会预渲染指针停留 200 ms 的那篇文章,覆盖了多数点击,又不必渲染页面上的每个链接。

<script type="speculationrules">
{
"prerender": [{
"where": { "and": [
{ "href_matches": "/articles/*" },
{ "not": { "selector_matches": ".no-prerender" } }
]},
"eagerness": "moderate"
}]
}
</script>

退出登录、一键操作之类绝不能预渲染的链接加上 no-prerender 类;预渲染的页面会运行脚本,加载时的副作用在用户决定访问之前就会发生。

统计页面浏览的代码必须等预渲染页面变为可见,否则每个悬停过的链接都算一次访问。

function onVisible(callback) {
if (document.prerendering) {
document.addEventListener('prerenderingchange', callback, { once: true });
} else {
callback(); // 未预渲染(或引擎不支持):页面已经可见
}
}
onVisible(() => sendPageView(location.href));

没有该 API 的引擎里 document.prerendering 为 undefined,else 分支把它当作普通的可见加载。

HTMLScriptElement.supports('speculationrules') 是能力测试。兜底插入一个 <link rel="prefetch">,在 Firefox 和 Chromium 中为下一个文档预热 HTTP 缓存而不预渲染。

function speculate(url) {
if (typeof HTMLScriptElement.supports !== 'undefined' && HTMLScriptElement.supports('speculationrules')) {
const script = document.createElement('script');
script.type = 'speculationrules';
script.textContent = JSON.stringify({ prefetch: [{ urls: [url] }] });
document.head.append(script);
return;
}
const link = document.createElement('link'); // 兜底:普通 prefetch,不预渲染
link.rel = 'prefetch';
link.href = url;
document.head.append(link);
}

脚本添加的规则与静态规则计入同一限制;移除脚本元素会取消其待处理的推测并释放容量。

规范

规范状态
无。