预提取的两种方法:<链接>标记和 HTTP 标头

Demián Renzulli
Demián Renzulli

在此 Codelab 中,您将通过两种方式实现预加载:使用 <link rel="prefetch"> 和使用 HTTP Link 标头。

示例应用是一个网站,其宣传着陆页提供商店最畅销的 T 恤的特惠折扣。由于着陆页链接到单个商品,因此可以肯定,有很大比例的用户会前往商品详情页面。因此,商品页面非常适合在着陆页上预加载。

衡量性能

首先确定基准性能:

  1. 点击 Remix to Edit 即可修改项目。
  2. 如需预览网站,请按 View App(查看应用)。然后按 Fullscreen(全屏)全屏
  3. 按 `Control+Shift+J`(在 Mac 上为 `Command+Option+J`)打开 DevTools。
  4. 点击网络标签页。

  5. Throttling 下拉列表中,选择 Fast 3G 以模拟慢速连接类型。

  6. 如需加载商品页面,请点击示例应用中的立即购买

product-details.html 页面的加载用时约为 600 毫秒:

显示 product-details.html 的加载时间的“网络”面板

如需改进导航体验,请在着陆页中插入 prefetch 代码以预加载 product-details.html 页面:

  • 将以下 <link> 元素添加到 views/index.html 文件的标头:
<!doctype html>
  <html>
    <head>
       <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet">

      <link rel="prefetch" href="/product-details.html" as="document">
      ...
</head>

as 属性是可选的,但建议使用该属性;该属性有助于浏览器设置正确的标头,并确定资源是否已在缓存中。此属性的示例值包括:documentscriptstylefontimageothers

如需验证预提取功能是否正常运行,请执行以下操作:

  1. 如需预览网站,请按 View App(查看应用)。然后按 Fullscreen(全屏)全屏
  2. 按 `Ctrl+Shift+J`(在 Mac 上,按 `Command+Option+J`)打开开发者工具。
  3. 点击网络标签页。

  4. 节流下拉列表中,选择快速 3G 以模拟连接类型较慢的情况。

  5. 清除“停用缓存”复选框。

  6. 重新加载应用。

现在,当着陆页加载时,product-details.html 页面也会加载,但优先级为最低:

网络面板,显示了预提取的 product-details.html。

网页会保留在 HTTP 缓存中五分钟,之后系统会应用文档的常规 Cache-Control 规则。在本例中,product-details.htmlcache-control 标头值为 public, max-age=0,这意味着该网页总共会保留 5 分钟。

重新评估效果

  1. 重新加载应用。
  2. 如需加载商品页面,请点击示例应用中的立即购买

请查看 Network 面板。与初始网络轨迹相比,有两个区别:

  • 大小列会显示“预提取缓存”,这表示相应资源是从浏览器的缓存而不是网络检索的。
  • 时间列显示,现在文档加载时间约为 10 毫秒。

与之前的版本(大约需要 600 毫秒)相比,这大约减少了 98%。

网络面板,显示从预提取缓存中检索到的 product-details.html。

额外提示:将 prefetch 用作渐进增强

最好将预提取作为渐进式增强功能来实现,以便为使用高速连接进行浏览的用户提供更好的体验。您可以使用 Network Information API 检查网络状况,并根据该状况动态注入预加载代码。这样,您可以最大限度地减少流量消耗,并为流量缓慢或流量费用较高的用户节省费用。

如需实现自适应预加载,请先从 views/index.html 中移除 <link rel="prefetch"> 标记:

<!doctype html>
  <html>
    <head>
       <meta charset="UTF-8">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet">
       <link rel="prefetch" href="/product-details.html" as="document">
       ...
    </head>

然后,将以下代码添加到 public/script.js 中,声明一个函数,以便在用户连接速度较快时动态注入 prefetch 标记:

function injectLinkPrefetchIn4g(url) {
    if (window.navigator.connection.effectiveType === '4g') {
        //generate link prefetch tag
        const linkTag = document.createElement('link');
        linkTag.rel = 'prefetch';
        linkTag.href = url;
        linkTag.as = 'document';

        //inject tag in the head of the document
        document.head.appendChild(linkTag);
    }
}

该函数的工作原理如下:

  • 它会检查 Network Information APIeffectiveType 属性,以确定用户是否使用的是 4G(或更快)连接。
  • 如果满足该条件,它会生成一个 <link> 标记,并将 prefetch 作为提示类型,在 href 属性中传递要预提取的网址,并在 as 属性中指明资源是 HTML document
  • 最后,它会在网页的 head 中动态注入脚本。

接下来,将 script.js 添加到 views/index.html 中,紧挨结束 </body> 标记前面:

<body>
      ...
      <script src="/script.js"></script>
</body>

在页面末尾请求 script.js 可确保在页面解析和加载后加载并执行它。

为确保预加载不会干扰当前网页的关键资源,请添加以下代码段,以便对 window.load 事件调用 injectLinkPrefetchIn4g()

<body>
      ...
      <script src="/script.js"></script>
      <script>
           window.addEventListener('load', () => {
                injectLinkPrefetchIn4g('/product-details.html');
           });
      </script>
</body>

着陆页现在仅在连接速度较快时预加载 product-details.html。如需验证这一点,请执行以下操作:

  1. 如需预览网站,请按 View App(查看应用)。然后按 Fullscreen(全屏)全屏
  2. 按 `Control+Shift+J`(在 Mac 上为 `Command+Option+J`)打开 DevTools。
  3. 点击网络标签页。
  4. 节流下拉列表中,选择在线
  5. 重新加载应用。

您应该会在“网络”面板中看到 product-details.html

网络面板,显示了预提取的 product-details.html。

如需验证系统不会在网速较慢时预提取商品页面,请执行以下操作:

  1. 在“节流”下拉列表中,选择3G 网络(速度缓慢)
  2. 重新加载应用。

广告网络面板应仅包含着陆页的资源,且不含 product-details.html

网络面板显示未预提取 product-details.html。

HTTP Link 标头可用于预提取与 link 标记相同类型的资源。确定何时使用哪种方法主要取决于您的偏好,因为两者的性能差异不大。在本例中,您将使用它预加载商品页面的主要 CSS,以进一步改进其呈现效果。

在着陆页的服务器响应中为 style-product.css 添加 HTTP Link 标头:

  1. 打开 server.js 文件,然后查找根网址 /get() 处理脚本。
  2. 在处理程序的开头添加以下行:
app.get('/', function(request, response) {
    response.set('Link', '</style-product.css>; rel=prefetch');
    response.sendFile(__dirname + '/views/index.html');
});
  1. 如需预览网站,请按 View App(查看应用)。然后按 Fullscreen(全屏)全屏
  2. 按 `Ctrl+Shift+J`(在 Mac 上,按 `Command+Option+J`)打开开发者工具。
  3. 点击网络标签页。
  4. 重新加载应用。

现在,系统会在着陆页加载后以最低优先级预提取 style-product.css

“Network”面板,显示已预提取的 style-product.css。

如需前往商品页面,请点击立即购买。查看 Network 面板:

网络面板,显示从预提取缓存中检索到的 style-product.css。

系统会从“预提取缓存”中检索 style-product.css 文件,并且只需 12 毫秒即可加载。