← 中文资源

简体中文版本

Speculation Rules 预渲染

Speculation Rules 让页面以 JSON 声明哪些 URL 做预取或完整预渲染:可能的下一次导航在隐藏上下文中渲染完成,点击时近乎瞬时呈现。

阅读英文原文

概念定义

页面携带 type 为 speculationrules 的脚本,包含 URL 列表或选择器加动作。浏览器依据 eagerness 与启发式决定何时预取或预渲染候选。预渲染页面是完整存活的隐藏文档:脚本已跑、布局已在,点击激活即换入当前页面。

工作机制

eagerness 分级排序候选:conservative 等待强意图,immediate 响应悬停或按下,eager 渲染所有匹配项。页面可通过 document.prerendering 与激活事件感知预渲染阶段,把分析与易变请求等副作用推迟到激活之后。

使用场景

高置信度的下一步:搜索首页的首批结果、文章导语后的付费墙页、结账续页。猜错的带宽与 CPU 随 eager 级别放大,应从 conservative 起步并统计哪些投机真正被激活。

常见误区

预渲染页面会执行代码:分析、会话、定时器若不等激活就运行,会记录幻影访问。部分模式下存储与 Cookie 按投机隔离,跨源预渲染另有约束。必须特性检测,把它严格当作渐进增强。

代码示例

<nav aria-label="Primary navigation">
  <button class="menu-toggle"
          aria-expanded="false"
          aria-controls="main-menu"
          aria-label="Toggle navigation menu">
    <span class="hamburger"></span>
  </button>

  <ul id="main-menu" class="menu" role="menubar">
    <li role="none">
      <a href="/" role="menuitem" aria-current="page">Home</a>
    </li>
    <li role="none">
      <a href="/products" role="menuitem">Products</a>
    </li>
    <li role="none">
      <a href="/about" role="menuitem">About</a>
    </li>
    <li role="none">
      <a href="/blog" role="menuitem">Blog</a>
    </li>
    <li role="none">
      <a href="/contact" role="menuitem">Contact</a>
    </li>
  </ul>
</nav>

<nav aria-label="Breadcrumb">
  <ol class="breadcrumb">
    <li><a href="/">Home</a></li>
    <li><a href="/products">Products</a></li>
    <li aria-current="page">Details</li>
  </ol>
</nav>

<style>
  .menu { list-style: none; display: flex; gap: 1rem; }
  .menu a { text-decoration: none; padding: 0.5rem 1rem; }
  .menu a[aria-current="page"] { font-weight: bold; border-bottom: 2px solid currentColor; }
  .breadcrumb { list-style: none; display: flex; gap: 0.5rem; }
  .breadcrumb li:not(:last-child)::after { content: " > "; }
</style>
public class StringBuilderManipulation {

    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder(64);

        sb.append("Hello");
        sb.append(" ");
        sb.append("World");
        System.out.println("Built: " + sb);

        sb.insert(5, " Java");
        System.out.println("After insert: " + sb);

        sb.delete(5, 10);
        System.out.println("After delete: " + sb);

        sb.replace(0, 5, "Hi");
        System.out.println("After replace: " + sb);

        sb.reverse();
        System.out.println("Reversed: " + sb);

        String csv = String.join(", ",
            "Apple", "Banana", "Cherry", "Date");
        System.out.println("CSV: " + csv);

        String formatted = String.format(
            "Name: %s, Age: %d, Score: %.2f",
            "Alice", 30, 95.5
        );
        System.out.println(formatted);

        String stripped = "  padded  ".strip();
        System.out.println("Stripped: '" + stripped + "'");
    }
}