プリフェッチの 2 つの方法: <link> タグと HTTP ヘッダー

Demián Renzulli 氏
Demián Renzulli 氏

この Codelab では、<link rel="prefetch"> と HTTP Link ヘッダーの 2 つの方法でプリフェッチを実装します。

このサンプルアプリは、プロモーションのランディング ページとして、そのショップのベストセラーの T シャツの特別割引を提供するウェブサイトです。ランディング ページは 1 つの商品にリンクされているため、商品の詳細ページに移動するユーザーの割合は高いと想定しても安全です。そのため、商品ページはランディング ページでプリフェッチする候補として有用です。

パフォーマンスの測定

まず、ベースライン パフォーマンスを確立します。

  1. [Remix to Edit] をクリックしてプロジェクトを編集可能にします。
  2. サイトをプレビューするには、[アプリを表示] を押してから、全画面表示 全画面表示 を押します。
  3. Ctrl+Shift+J キー(Mac の場合は Command+Option+J キー)を押して DevTools を開きます。
  4. [Network] タブをクリックします。

  5. [Throttling] プルダウン リストで [Fast 3G] を選択して、低速な接続タイプをシミュレートします。

  6. 商品ページを読み込むには、サンプルアプリで [Buy now] をクリックします。

product-details.html ページの読み込みには約 600 ミリ秒かかります。

product-details.html の読み込み時間を示す [Network] パネル

ナビゲーションを改善するには、ランディング ページに prefetch タグを挿入して product-details.html ページをプリフェッチします。

  • views/index.html ファイルのヘッダーに次の <link> 要素を追加します。
<!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 属性は省略可能ですが、指定することをおすすめします。この属性を指定することで、ブラウザが適切なヘッダーを設定し、リソースがすでにキャッシュに存在するかどうかを判断できます。この属性の値の例: documentscriptstylefontimageその他

プリフェッチが機能していることを確認するには:

  1. サイトをプレビューするには、[アプリを表示] を押してから、全画面表示 全画面表示 を押します。
  2. Ctrl+Shift+J キー(Mac の場合は Command+Option+J キー)を押して DevTools を開きます。
  3. [Network] タブをクリックします。

  4. [Throttling] プルダウン リストで [Fast 3G] を選択して、低速な接続タイプをシミュレートします。

  5. [キャッシュを無効にする] チェックボックスをオフにします。

  6. アプリを再読み込みします。

これで、ランディング ページが読み込まれるときに product-details.html ページも読み込まれるようになりますが、優先度は最も低くなります。

product-details.html のプリフェッチが表示されている [Network] パネル。

ページは HTTP キャッシュに 5 分間保持されます。その後は、ドキュメントの通常の Cache-Control ルールが適用されます。この例では、product-details.htmlpublic, max-age=0 の値を持つ cache-control ヘッダーがあります。これは、ページが合計 5 分間保持されることを意味します。

パフォーマンスを再評価する

  1. アプリを再読み込みします。
  2. 商品ページを読み込むには、サンプルアプリで [Buy now] をクリックします。

[ネットワーク] パネルを確認します。最初のネットワーク トレースとの違いは 2 つあります。

  • [Size] 列には「プリフェッチ キャッシュ」と表示されています。これは、このリソースがネットワークではなくブラウザのキャッシュから取得されたことを意味します。
  • [時間] 列に、ドキュメントの読み込みにかかる時間が約 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(またはそれより高速な)接続を使用しているかどうかを判断します。
  • この条件が満たされると、ヒントのタイプとして prefetch を持つ <link> タグを生成し、プリフェッチされる URL を href 属性で渡し、リソースが as 属性の HTML document であることを示します。
  • 最後に、スクリプトをページの head に動的に追加します。

次に、views/index.html</body> 終了タグの直前に script.js を追加します。

<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. サイトをプレビューするには、[アプリを表示] を押してから、全画面表示 全画面表示 を押します。
  2. Ctrl+Shift+J キー(Mac の場合は Command+Option+J キー)を押して DevTools を開きます。
  3. [Network] タブをクリックします。
  4. [スロットリング] プルダウン リストで [オンライン] を選択します。
  5. アプリを再読み込みします。

[Network] パネルに product-details.html が表示されます。

product-details.html のプリフェッチが表示されている [Network] パネル。

接続速度が遅い場合に商品ページがプリフェッチされないことを確認する手順は次のとおりです。

  1. [Thottling] プルダウン リストで [Slow 3G] を選択します。
  2. アプリを再読み込みします。

[ネットワーク] パネルには、product-details.html のないランディング ページのリソースのみが表示されます。

product-details.html がプリフェッチされていないことを示す [Network] パネル。

HTTP Link ヘッダーは、link タグと同じタイプのリソースをプリフェッチするために使用できます。パフォーマンスの違いはそれほどないため、どちらを使用するべきかは、主にユーザーの好みによって決まります。今回は、商品ページのメインの CSS をプリフェッチしてレンダリングをさらに改善します。

ランディング ページのサーバー レスポンスに、style-product.css の HTTP Link ヘッダーを追加します。

  1. server.js ファイルを開き、ルート URL(/)の get() ハンドラを探します。
  2. ハンドラの先頭に次の行を追加します。
app.get('/', function(request, response) {
    response.set('Link', '</style-product.css>; rel=prefetch');
    response.sendFile(__dirname + '/views/index.html');
});
  1. サイトをプレビューするには、[アプリを表示] を押してから、全画面表示 全画面表示 を押します。
  2. Ctrl+Shift+J キー(Mac の場合は Command+Option+J キー)を押して DevTools を開きます。
  3. [Network] タブをクリックします。
  4. アプリを再読み込みします。

ランディング ページが読み込まれた後に、style-product.css が最も低い優先度でプリフェッチされるようになりました。

style-product.css のプリフェッチが表示されている [ネットワーク] パネル。

商品ページに移動するには、[今すぐ購入] をクリックします。[Network] パネルを確認します。

プリフェッチ キャッシュから取得した style-product.css が表示されている [ネットワーク] パネル。

style-product.css ファイルは「プリフェッチ キャッシュ」から取得され、読み込みには 12 ミリ秒しかかからなかった。