配了三年性能优化,今天才发现页面加载的瓶颈根本不在代码里——Chrome 自己会把下一页提前跑完,Speculation Rules API 把这件事彻底变了

用户说页面卡,我盯了三年 Lighthouse——今天发现根子不在代码,在浏览器”提前跑”这件事里。Chrome 自己会把下一页在后台提前渲染完,等用户点的时候页面已经就位了,根本不用等加载。这个能力叫 Speculation Rules API,是 Chrome 109 就支持的,但2026年它真正开始大规模落地了。

这件事把性能优化的逻辑彻底变了:以前你是在”让请求变快”,现在你是在”让请求提前发生”。

预渲染和预获取,是两码事

Speculation Rules API 支持两种提前加载策略。

Prefetch 只下载 HTML 文档,不渲染、不执行脚本、不加载子资源。它主要改善的是 TTFB(首字节时间),省一次网络往返。用户点链接时,浏览器已经在缓存里拿到了 HTML,后续解析还是要从头来。

Prerender 更激进。它在后台打开一个隐藏的 tab,把整个页面跑完——HTML、CSS、JS、图片全部加载,JavaScript 全部执行,等用户点的时候直接把这个 tab 换上来。用户感知到的 LCP 可以从几秒降到几十毫秒。

Chrome 121 开始还多了一个中间选项:prerender_until_script。它从下载 HTML 开始渲染、加载所有子资源,但遇到阻塞型 script 标签就暂停,不执行 JS。这对有分析脚本或第三方脚本的页面特别有用——既拿到了渲染红利,又不会让脚本提前触发。

eagerness 配置:速度与浪费之间的天平

预渲染的核心矛盾是:提前越多体验越好,但猜错链接就越是浪费带宽和内存。eagerness 就是用来调这个平衡的,有四个档位。

conservative 档只在用户按下去(pointerdown)那一刻才启动预渲染,预判时间最短,但浪费最少,适合不可靠的链接。moderate 档在鼠标悬停 200 毫秒后触发,这是多数内容站点的最佳平衡点——用户扫读菜单时不会误触发,真正要点的链接有足够时间预渲染。eager 档在链接进入视口就启动(桌面端悬停 10ms 后,移动端进入视口 50ms 后),适合高可信的导航。immediate 档在规则解析完立刻全量预渲染,只适合规则已知、跳转路径确定的场景(比如下单流程的下一步)。

Chrome 对并发数也有限制:immediate/eager 档最多 50 个 prefetch 和 10 个 prerender;moderate/conservative 档最多 2 个 prerender,而且是最先预渲染的会被踢出(FIFO)。这个限制让 moderate 成了大多数场景的安全默认值。

document rules:不用列 URL,浏览器自己找

早期实现里你要手动列出要预渲染的 URL 列表,这件事在动态站里基本不可维护。Chrome 122 引入了 document rules,让浏览器根据条件自动从页面里找链接。

// 所有同源链接预渲染,排除 logout 和购物车
// 链接悬停 200ms 后触发
// 这套规则写一次,整站生效

这规则告诉 Chrome:把同站点的链接都预渲染一遍,但 logout 和购物车这种有副作用的页面要排除。这套规则写一次,整站生效,不用每个页面单独维护 URL 列表。

href_matches 支持 URLPattern 语法,可以按路径、参数、锚点做过滤。selector_matches 则按 CSS 选择器匹配,用法更灵活。

有副作用的页面绝对不能预渲染

这是最容易踩的坑。Prerender 在后台跑 JS,所以任何有副作用的操作——logout、加入购物车、一次性 token 验证、埋点上报——都会在用户还没点的时候就触发了一遍。

统计数据最典型:埋点会在预渲染时发一次、页面激活时再发一次,流量直接翻倍。解决方法是用 document.prerendering 判断当前是否在预渲染状态,只有真正激活时才初始化分析脚本。

// 预渲染时等激活后再初始化
// 正常直接加载直接初始化

其他要排除的典型场景:带有 POST 操作的链接、带查询参数的状态变更 URL、一次性邀请链接。所有这些都要在 where 条件里用 not 明确剔除。

Chrome 144 新特性:prerender_until_script

2026 年 1 月,Chrome 144 把 prerender_until_script 正式落地。这是 prefetch 和 full prerender 之间的第三种选择:下载 HTML → 开始渲染 → 加载所有子资源 → 在阻塞型 script 处暂停。用户点进来时,页面渲染已经走在前面,阻塞脚本再接着跑。

这个模式的价值在于:多数页面最耗时的不是网络,是 JS 执行。对于一个以内容为主、只在页脚有个第三方脚本的页面,prerender_until_script 几乎等价于完整预渲染,但不会触发那个第三方脚本的副作用。

怎么落地:两行代码的事

在页面底部加一个 script type= speculationrules 就行。

// 预渲染所有 blog 链接,悬停触发

浏览器不支持这个 API 时会直接忽略,不报错、不降级,就是正常导航。feature detection 写法。

// 检测支持

也可以通过 HTTP 响应头 Speculation-Rules 注入,这样 CDN 层也可以统一管理,不用改 HTML。

浏览器支持现状

Chrome 109+ 和 Edge 109+ 已经全量支持。Firefox 表明了支持 prefetch 的标准化意向,但尚未实现。Safari 26.2 有关闭的实现但默认不开启。所以它是一个渐进增强:Chromium 用户拿到完整的即时导航体验,其他浏览器用户正常加载,代码不用任何修改。

Google Search 已经在用这套机制给结果页做即时预览了,你在自己的站上用的其实是和 Google 搜索一样的底层能力。

怎么开始

这件事不需要重构、不需要换框架,一行 JSON 就能接入。第一步先在生产环境找一条高可信、高流量的链接——内容站的”下一篇”、电商的”确认订单”页——加 moderate 预渲染,然后用 Chrome DevTools → Application → Background Services → Speculative Loads 看板看激活率和预渲染成功率。

等数据表明浪费可控,再逐步扩展到文档站的章节链接、博客的标签页。核心原则只有一条:prefetch 可以宽,prerender 必须窄。

配了三年性能优化,今天终于发现:让页面变快这件事,有时候根本不用改一行代码——让浏览器自己决定什么时候去拿下一页,才是最高效的优化。

评论区

0 条评论

登录后可评论。

阿速·性能优化 176 阅读