NoState Prefetch のご紹介

Katie Hempenius
Katie Hempenius

はじめに

NoState Prefetch は Chrome の新しいメカニズムで、サポートが終了した事前レンダリング プロセスに代わるもので、<link rel="prerender"> などの機能で活用されています。事前レンダリングと同様に、リソースを事前に取得します。ただし事前レンダリングとは異なり、JavaScript を実行したり、ページの一部を事前にレンダリングしたりすることはありません。NoState のプリフェッチの目標は、事前レンダリングよりも使用するメモリを減らしながら、ページの読み込み時間を短縮することです。

NoState Prefetch は API ではなく、さまざまな API や機能を実装するために Chrome で使用されるメカニズムです。Resource Hints API と Chrome のアドレスバーによるページのプリフェッチは、どちらも NoState Prefetch を使用して実装されています。Chrome 63 以降を使用している場合、ブラウザはすでに <link rel="prerender"> などの機能に NoState Prefetch を使用しています。

この記事では、NoStatePrefetch の仕組み、導入する動機、Chrome のヒストグラムを使用して使用状況に関する統計情報を確認する手順について説明します。

目的

NoState Prefetch を導入する主な動機は 2 つあります。

メモリ使用量を削減する

NoState のプリフェッチは、最大 45 MiB のメモリのみを使用します。NoState Prefetch の主なメモリコストはプリロード スキャナのメンテナンスであり、このコストはさまざまなユースケースで比較的一定です。フェッチのサイズまたはボリュームを増やしても、NoState Prefetch によって消費されるメモリの量に大きな影響はありません。

一方、事前レンダリングは通常 100 MiB のメモリを消費し、メモリ消費量は 150 MiB が上限となります。メモリ消費量が多いため、ローエンド(RAM が 512 MB 以下)のデバイスには適していません。そのため、Chrome はローエンド デバイスでは事前レンダリングを行わず、事前接続を行います。

新しいウェブ プラットフォーム機能のサポートを促進する

事前レンダリングでは、ユーザー向けの操作(音楽や動画の再生など)やステートフル アクション(セッションの変更、ローカル ストレージなど)は発生しません。しかし、ページのレンダリング中にこのようなアクションが発生しないようにすることは困難で複雑な場合があります。NoState Prefetch は事前にリソースを取得するだけで、コードの実行やページのレンダリングは行いません。これにより、ユーザー向けのステートフル アクションの発生を簡単に防止できます。

実装

NoState Prefetch の仕組みは次のとおりです。

  1. NoStatePrefetch がトリガーされる。

    次の 2 つの条件が満たされている場合、事前レンダリングのリソースヒント(<link rel="prerender">)と一部の Chrome 機能は NoState Prefetch をトリガーします。a)ユーザーがローエンド デバイスを使用していないこと、b)ユーザーがモバイル ネットワークに接続していない。

  2. NoState Prefetch 用の新しい専用レンダラが作成されます。

    Chrome では、「レンダラ」とは、HTML ドキュメントを取得して解析し、そのレンダリング ツリーを構築して、結果を画面に描画するプロセスを指します。Chrome の各タブと各 NoState Prefetch プロセスには、分離するための独自のレンダラがあります。これにより、なんらかの問題が発生した場合(タブのクラッシュなど)の影響を最小限に抑えられるほか、悪意のあるコードが他のタブやシステムの他の部分にアクセスすることを防止できます。

  3. NoState Prefetch で読み込まれているリソースが取得されます。次に、HTMLPreloadScanner がこのリソースをスキャンして、取得が必要なサブリソースを検出します。 メインリソースまたはそのサブリソースのいずれかに Service Worker が登録されている場合、これらのリクエストは適切な Service Worker を経由します。

    NoState Prefetch は GET HTTP メソッドのみをサポートしています。他の HTTP メソッドを使用する必要があるサブリソースは取得しません。また、ユーザー操作(認証ポップアップ、SSL クライアント証明書、手動オーバーライドなど)を必要とするリソースも取得されません。

  4. 取得されるサブリソースは、ネット優先度「IDLE」で取得されます。

    「IDLE」ネット優先度は、Chrome のネット優先度の中で最も低い値です。

  5. NoState Prefetch で取得されたすべてのリソースは、キャッシュ ヘッダーに従ってキャッシュに保存されます。

    NoState Prefetch は、no-store Cache-Control ヘッダーを除くすべてのリソースをキャッシュに保存します。Vary レスポンス ヘッダーまたは no-cache Cache-Control ヘッダーがある場合、またはリソースが 5 分以上経過している場合、リソースは使用前に再検証されます。

  6. すべてのサブリソースが読み込まれた後、レンダラが強制終了される。

    サブリソースがタイムアウトした場合、レンダラは 30 秒後に強制終了されます。

  7. ブラウザは、Cookie ストアとローカル DNS キャッシュの更新以外、状態の変更を行いません。これは「NoState Prefetch」の「NoState」であるため、注意する必要があります。

    「通常の」ページ読み込みプロセスのこの時点で、ブラウザはおそらくブラウザの状態を変更する処理(JavaScript の実行、sessionStoragelocalStorage の変更、音楽や動画の再生、History API の使用、ユーザーへのメッセージ表示など)を行います。NoState Prefetch で発生する状態変更は、レスポンスの受信時の DNS キャッシュの更新と、レスポンスに Set-Cookie ヘッダーが含まれている場合の Cookie ストアの更新のみです。

  8. リソースが必要になると、ブラウザ ウィンドウに読み込まれます。

    ただし、事前レンダリングされたページとは異なり、ページはすぐに表示されるわけではなく、ブラウザでレンダリングされる必要があります。ブラウザは、NoState Prefetch に使用していたレンダラを再利用せず、新しいレンダラを使用します。事前にページをレンダリングしないことで、NoStatePrefetch のメモリ消費量を削減できますが、ページの読み込み時間への影響も軽減されます。

    ページに Service Worker がある場合、このページ読み込みは Service Worker を経由します。

    ページが必要になるまでに NoState プリフェッチがサブリソースの取得を完了していなかった場合、ブラウザは NoState プリフェッチが中断した時点からページ読み込みプロセスを続行します。ブラウザは引き続きリソースを取得する必要がありますが、NoState プリフェッチが開始されていない場合に必要なリソースの数を減らす必要があります。

ウェブ解析への影響

NoState Prefetch を使用して読み込まれたページは、クライアントサイドとサーバーサイドのどちらでデータを収集するかによって、ウェブ解析ツールによって登録されるタイミングが若干異なります。

クライアントサイドの分析スクリプトは、ページがユーザーに表示されるときにページビューを登録します。これらのスクリプトは JavaScript の実行に依存しており、NoState Prefetch は JavaScript を実行しません。

サーバーサイドの分析ツールは、リクエストの処理時に指標を登録します。NoState Prefetch を介して読み込まれたリソースの場合、リクエストが処理されてから、クライアントによって実際にレスポンスが使用されるまでにかなりの時間差が生じることがあります(実際に使用する場合)。Chrome 69 以降では、通常のブラウジングと区別できるように、NoState Prefetch のすべてのリクエストにヘッダー Purpose: Prefetch が追加されています。

詳細を確認

NoStatePrefetch は Chrome 63 で 2017 年 12 月にリリースされました。現在、以下の用途で使用しています。

  • prerender リソースヒントを実装する
  • Google 検索の検索結果の最初の結果を取得する
  • Chrome のアドレスバーで、次にアクセスされる可能性が高いと予測されたページを取得します

Chrome Internals を使用すると、NoStatePrefetch がどのように使用されているかを確認できます。

NoState Prefetch で読み込まれたサイトのリストを表示するには、chrome://net-internals/#prerender にアクセスします。

NoState プリフェッチの使用状況に関する統計情報を確認するには、chrome://histograms にアクセスして「NoStatePrefetch」を検索します。NoState プリフェッチの用途ごとに 1 つずつ、3 種類の NoState プリフェッチ ヒストグラムがあります。

  • 「NoStatePrefetch」(事前レンダリングのリソースヒントによる使用状況の統計情報)
  • 「gws_NoStatePrefetch」(Google 検索結果ページでの使用に関する統計情報)
  • 「omnibox_NoStatePrefetch」(Chrome アドレスバーの使用状況に関する統計情報)