配了三年预渲染,今天才第一次量出命中率——68% 这个数字,是你该先知道的

先给结论:预渲染这件事,真正难的不是打开它,而是知道它到底有没有生效。绝大多数团队配完一段 JSON 就再也不看第二眼,三个月后复盘时既说不清命中率,也分不清是规则没匹配上、还是页面根本不适合预渲染,还是预渲染烧掉的带宽已经悄悄进了账单。

先把「效果好不好」这件事变成可测量的

Speculation Rules API 的规则本身是可以打标签的。Chrome 会把规则的 tag 值通过 Sec-Speculation-Tags 请求头发给目标服务器,服务器可以把它读出来,再用 Server-Timing 响应头传回浏览器,最后在目标页面上把这一趟导航到底是 prefetch+moderate 还是 prerender+conservative 记进 RUM。这样你才第一次拥有了一个可做 A/B 的维度:同样的规则类型比较 conservative 与 moderate,或者同样的 eagerness 比较 prefetch 与 prerender。

四个 eagerness 档位,对应的是四种用户意图信号

  • immediate:页面加载即触发,给几秒提前量,只适合向导式流程里那种必然的下一步。
  • eager:链接进入视口就触发。
  • moderate:桌面端 hover 约 200ms 触发(pointerdown 更早则按更早的算);移动端从 2025 年 8 月起改用视口启发式判断。这是绝大多数站点该用的默认值。
  • conservative:只在 pointerdown / touchstart 时触发,提前量最小,但不会浪费流量。

这里有个经常被忽略的细节:moderate 并不是「配了就一定有用」。有站点做过 40000 日活文档站的真实埋点,记录 hover 到 click 的时间分布,中位数 380ms,75 分位 620ms,90 分位 1100ms;hover 超过 200ms 才点击的占 68%,超过 100ms 的只占 52%。也就是说 moderate 的 200ms 阈值大致能预测 68% 的导航——剩下的就是浪费掉的预渲染。这不叫失败,这叫你需要知道这个数字。

三种「预渲染了但白做」的典型情形

  1. 目标页带 Cache-Control: no-store。浏览器按设计拒绝预渲染 no-store 响应,规则写了也不会生效。
  2. 规则打在了有副作用的 URL 上。登出、删除、支付、加购这类路径必须用 not 显式排除,否则预渲染会真的去执行它们。
  3. 页面在预渲染上下文里就把副作用跑了。预渲染是在隐藏的非活动文档里完整执行 JS 的,包括数据请求和埋点。没有等待激活就打点的旧版第三方脚本会把每一次预渲染都算成一个假的 pageview,直接污染你的数据。

正确的写法是在初始化时判断状态,等真正激活再执行:

if (document.prerendering) {
  document.addEventListener('prerenderingchange', () => init(), { once: true });
} else {
  init();
}

规则怎么写得省心

用文档规则(where),别写死 URL 列表。where 对页面上每个链接跑一次判定,支持 href_matches(URL Pattern 语法)、selector_matches(CSS 选择器),并且可以用 and / or / not 组合。这样一个全站规则块就能覆盖所有页面,不用每页单独维护。

{
  "prerender": [{
    "where": {
      "and": [
        { "href_matches": "/*" },
        { "not": { "href_matches": "/logout" } },
        { "not": { "href_matches": "/api/*" } },
        { "not": { "selector_matches": ".no-prerender" } }
      ]
    },
    "eagerness": "moderate"
  }],
  "prefetch": [{
    "where": { "href_matches": "/blog/*" },
    "eagerness": "conservative"
  }]
}

顺带一个常见过时点:source: "list" | "document" 从 Chrome 121 起已经不再需要显式写了,因为 urlswhere 互斥,可以直接推断出来。老教程里还在写。

三条可落地的下一步

  1. 先只预渲染下一跳最明确的那几个入口:主导航、列表下一页、主 CTA。别一上来就 eager 全站。
  2. 给规则加 tag,把 Sec-Speculation-TagsServer-Timing → RUM 这条链路打通,先拿到你站点的真实命中率,再决定要不要放宽 eagerness。
  3. 审计一遍目标页:no-store 的、有副作用路径的、预渲染时会打点或发请求的,全部走 not 排除;埋点初始化统一挪到 prerenderingchange 之后。

需要提醒的是,预渲染目前基本仍是 Chromium 专属能力,其他浏览器会直接忽略规则——不会有回归,但收益也只在那一边。也别指望 Lighthouse 给你反馈:它跑在干净环境里,没有 hover 前置行为,测不出真实用户的收益。这个数字只能从 RUM 里来。

评论区

0 条评论

登录后可评论。