Early Hints とともにサーバーの思考時間を使用してページ読み込みを高速化

重要なサブリソースに関するヒントをサーバーからブラウザに送信する方法を確認しましょう。

Kenji Baheux 氏
Kenji Baheux

早期ヒントとは何ですか?

ウェブサイトは時間の経過とともに洗練され、そのため、リクエストされたページの HTML を生成するために、サーバーが重要な作業(データベースへのアクセス、オリジン サーバーへのアクセスなど)を行う必要があるのは珍しいことではありません。残念ながら、この「サーバーの思考時間」により、ブラウザがページのレンダリングを開始する前に余分なレイテンシが発生します。実際に、サーバーが応答を準備するのに時間がかかる間、接続は実質的にアイドル状態になります。

サーバーのページの読み込みと他のリソースの読み込みの間に 200 ミリ秒のタイムギャップがあることを示す画像。
早期のヒントがない場合: メインリソースへの応答方法を決定しているすべてのことがサーバーでブロックされます。

Early Hints は HTTP ステータス コード(103 Early Hints)で、最終的なレスポンスの前に予備 HTTP レスポンスを送信するために使用される。これにより、サーバーがメインリソースの生成でビジー状態にあるときに、そのページで使用される可能性の高い重要なサブリソース(ページのスタイルシート、重要な JavaScript など)やオリジンに関するヒントを、サーバーからブラウザに送信できます。ブラウザはメインのリソースを待機している間に、これらのヒントを使用して接続をウォームアップし、サブリソースをリクエストできます。言い換えれば、Early Hints は、ブラウザで事前になんらかの作業を行うことで、このような「サーバーの思考時間」を利用してページの読み込みを高速化します。

早期ヒントによってページが部分的なレスポンスを送信する仕組みを示す画像。
早期のヒント: サーバーはリソースヒントを含む部分的なレスポンスを提供する一方で、最終的なレスポンスを決定できます

場合によっては、Largest Contentful Paint のパフォーマンスが、ShopifyCloudflare で観測された数百ミリ秒から最大 1 秒速くなります。

2 つのサイトの比較。
WebPageTest(Moto G4 - DSL)で実施した、テスト ウェブサイトでの初期ヒントの適用前と実施後の比較

早期ヒントの実装

トピックに入る前に、サーバーが 200(またはその他の最終レスポンス)をすぐに送信できる場合、早期ヒントは役に立たないことにご注意ください。そのような場合は、代わりにメイン レスポンス(Link rel HTTP ヘッダー)またはメイン レスポンス(<link> 要素)で、通常の link rel=preload または link rel=preconnect を使用することを検討してください。サーバーでメインのレスポンスの生成に少し時間がかかる場合は、この後に進んでください。

早期ヒントを活用するための最初のステップは、上位のランディング ページ、つまりユーザーがウェブサイトにアクセスしたときに通常最初に表示されるページを特定することです。ホームページのほか、他のウェブサイトから多くのユーザーがアクセスしている場合は人気の商品リスティング ページが該当します。これらのエントリ ポイントが他のページよりも重要である理由は、ユーザーがウェブサイト内を移動すると、Early Hints の有用性が低下するためです(つまり、ブラウザは 2 回目または 3 回目のナビゲーションに必要なすべてのサブリソースを持つ可能性が高くなります)。そして、良い第一印象を与えることも常に良いアイデアです。

これでランディング ページの優先順位リストが得られたので、次のステップでは、最初の概算として、事前接続またはプリロードのヒントに適した送信元またはサブリソースを特定します。通常は、Largest Contentful PaintFirst Contentful Paint などの主要なユーザー指標に寄与するオリジンとサブリソースです。具体的には、同期 JavaScript、スタイルシート、ウェブフォントなど、レンダリングをブロックするサブリソースを探します。同様に、主要なユーザー指標に大きく影響するサブリソースをホストしているオリジンを探します。注: メインのリソースですでに <link rel=preconnect> または <link rel=preload> を使用している場合は、これらのオリジンやリソースを早期ヒントの対象とみなすことができます。詳しくは、こちらの記事をご覧ください。

2 つ目のステップでは、古くなった可能性がある、またはメインリソースで使用されなくなったリソースやオリジンで、早期ヒントが使用されるリスクを最小化します。たとえば、更新とバージョニングが頻繁に行われるリソース(example.com/css/main.fa231e9c.css など)は最適な選択ではない場合があります。なお、この懸念は早期ヒントに固有のものではなく、rel=preload または rel=preconnect が存在する可能性があるすべてのリンクに適用されます。このような詳細情報は、自動化またはテンプレート化で処理するのが最も効果的です(たとえば、手動プロセスでは、link rel=preload と、リソースを使用する実際の HTML タグとの間でハッシュまたはバージョンの URL が一致しなくなる可能性が高くなります)。

例として、次のフローを考えてみます。

GET /main.html
Host: example.com
User-Agent: [....] Chrome/103.0.0.0 [...]

サーバーは main.abcd100.css が必要になると予測し、Early Hints を使用してプリロードを提案します。

103 Early Hints
Link: </main.abcd100.css>; rel=preload; as=style
[...]

しばらくすると、リンクされている CSS を含むウェブページが配信されます。残念ながら、この CSS リソースは頻繁に更新されており、メインリソースは予測された CSS リソース(abcd100)よりすでに 5 バージョン分先(abcd105)になっています。

200 OK
[...]
<HTML>
<head>
   <title>Example</title>
   <link rel="stylesheet" href="/main.abcd105.css">

一般的に、かなり安定していて、メインのリソースの結果から大きく依存するリソースとオリジンを目標にする。必要に応じて、主要なリソースを 2 つに分割することを検討してください。一つは初期ヒントで使用するように設計された安定した部分と、メインのリソースがブラウザによって受け取られた後にフェッチされる動的な部分です。

<HTML>
<head>
   <title>Example</title>
   <link rel="stylesheet" href="/main.css">
   <link rel="stylesheet" href="/experimental.3eab3290.css">

最後に、サーバー側で、Early Hints に対応しているブラウザから送信された主なリソース リクエストを探し、103 の早期ヒントですぐに対応します。103 レスポンスには、関連する事前接続とプリロードのヒントを含めます。メインリソースの準備ができたら、通常のレスポンスでフォローアップします(たとえば、成功した場合は 200 OK)。下位互換性を確保するため、最終レスポンスに Link HTTP ヘッダーも含めることをおすすめします。さらに、メインリソースの生成の一環として明らかになった重要なリソースで補強することもあります(たとえば、「Split in two」という提案に従っている場合、キーリソースの動的部分など)。この場合は次のようになります。

GET /main.html
Host: example.com
User-Agent: [....] Chrome/103.0.0.0 [...]
103 Early Hints
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script

しばらくすると次のようになります。

200 OK
Content-Length: 7531
Content-Type: text/html; charset=UTF-8
Content-encoding: br
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script
Link: </experimental.3eab3290.css>; rel=preload; as=style
<HTML>
<head>
   <title>Example</title>
   <link rel="stylesheet" href="/main.css">
   <link rel="stylesheet" href="/experimental.3eab3290.css">
   <script src="/common.js"></script>
   <link rel="preconnect" href="https://fonts.googleapis.com">

ブラウザ サポート

103 の早期ヒントはすべての主要なブラウザでサポートされていますが、早期のヒントで送信できるディレクティブはブラウザによって異なります。

事前接続のサポート:

対応ブラウザ

  • 103
  • 103
  • 120
  • 17

プリロードのサポート:

対応ブラウザ

  • 103
  • 103
  • x

サーバー サポート

ここでは、一般的な OSS HTTP サーバー ソフトウェアにおける初期ヒントのサポートレベルを簡単にまとめます。

アーリーヒントを有効にすることで、

次のいずれかの CDN またはプラットフォームを使用している場合は、Early Hints を手動で実装する必要がない場合があります。ソリューション プロバイダのオンライン ドキュメントで Early Hints をサポートしているかどうかを知るか、以下のリストをご覧ください(すべてを網羅しているわけではありません)。

Early Hints に対応していないクライアントの問題を回避する

100 の範囲の情報 HTTP レスポンスは HTTP 標準の一部ですが、103 Early Hints がリリースされる前は、一般的なウェブ ブラウジングにほとんど使用されていなかったため、一部の古いクライアントや bot はこれに苦戦しているかもしれません。

sec-fetch-mode: navigate HTTP リクエスト ヘッダーを送信するクライアントに応答する場合にのみ 103 の早期ヒントを出力することで、後続のレスポンスを待つことを理解している新しいクライアントにのみこのようなヒントが送信されるようにする必要があります。また、早期ヒントはナビゲーション リクエストでのみサポートされているため(現在の制限事項を参照)、他のリクエストで不必要にこれらのヒントを不必要に送信しないことにも利点があります。

また、早期のヒントは HTTP/2 または HTTP/3 接続経由でのみ送信することをおすすめします

高度なパターン

主要なランディング ページに早期のヒントを完全適用済みで、さらなる機会をお探しの場合は、次の高度なパターンにご興味がおありでしょうか。

一般的なユーザー ジャーニーの nn ページ目をリクエストしたユーザーについては、ページの下の方にあるコンテンツ、つまり優先度の低いリソースで早期のヒントを使用するという意味で、早期のヒントの回答を適応させることをおすすめします。優先度の高いレンダリング ブロックのサブリソースやオリジンに重点を置くことを推奨したため、直感に反しているように思えるかもしれません。しかし、ユーザーがしばらく移動していた頃には、ブラウザにすでに重要なリソースがすべて用意されている可能性が高いです。ここからは、優先度の低いリソースに注意を向ける方が理にかなっています。たとえば、商品画像を読み込むための早期のヒントや、あまり一般的でないユーザー操作にのみ必要な JS/CSS を追加しています。

現在の制限事項

Chrome に実装されている早期ヒントには以下の制限があります。

  • ナビゲーション リクエスト(最上位ドキュメントのメインリソース)でのみ使用できます。
  • preconnectpreload のみをサポートします(つまり、prefetch はサポートされていません)。
  • 最終的な応答でアーリーヒントに続いてクロスオリジン リダイレクトが行われた場合、Chrome は Early Hints を介して取得したリソースと接続をドロップします。

他のブラウザにも同様の制限があり、103 個の早期ヒントは preconnect のみに制限されます。

次のステップ

コミュニティの要望に応じて、早期のヒントの実装を以下の機能で補強する場合があります。

  • 早期ヒントはサブリソース リクエストで送信されます。
  • iframe のメインリソース リクエストで早期のヒントが送信されます。
  • 初期ヒントでのプリフェッチのサポート。

優先すべき点や、早期ヒントをさらに改善する方法について、ご意見をぜひお寄せください。

下半期/プッシュとの関係

非推奨の HTTP2/push 機能に精通している方々は、Early Hints との違いに気付くかもしれません。Early Hints では、ブラウザが重要なサブリソースの取得を開始するにはラウンド トリップが必要ですが、HTTP2/push を使用すると、サーバーはレスポンスと一緒にサブリソースの push を開始する可能性があります。これは驚くべきことに聞こえますが、これは重要な構造上の欠点をもたらしました。HTTP2/Push では、ブラウザにあるサブリソースの push を避けるのが極めて困難でした。この「押しすぎる」効果により、ネットワーク帯域幅の使用効率が下がり、パフォーマンス上のメリットが大幅に損なわれました。全体として、Chrome のデータによると、HTTP2/Push はウェブ全体のパフォーマンスに悪影響を及ぼしています。

一方、Early Hints は、予備レスポンスを送信する機能とヒント(ヒント)を組み合わせて、実際に必要なものをブラウザが取得(接続)するので、実際のパフォーマンスが優れています。Early Hints は、HTTP2/Push が理論上対処できるすべてのユースケースを網羅しているわけではありませんが、ナビゲーションを高速化するためのより実用的なソリューションであると考えています。

Pierre Bamin 氏によるサムネイル画像