Fetch Priority API を使用してリソースの読み込みを最適化する

Fetch Priority API は、ブラウザに対するリソースの相対的な優先度を示します。読み込みを最適化し、Core Web Vitals を改善できます。

Addy Osmani
Addy Osmani
Leena Sohoni
Leena Sohoni
Patrick Meenan
Patrick Meenan

対応ブラウザ

  • 102
  • 102
  • x
  • 17.2

ソース

ブラウザはウェブページを解析し、画像、スクリプト、CSS などのリソースの検出とダウンロードを開始すると、最適な順序でダウンロードできるようにフェッチ priority を割り当てます。通常、リソースの優先度は、リソースの内容とドキュメント内の場所によって決まります。たとえば、ビューポート内の画像の優先度を High にし、<head><link> を使用する早期に読み込まれるレンダリングをブロックする CSS の優先度を Very High とします。ブラウザは、適切な優先度を割り当てるのが得意ですが、すべてのケースで最適であるとは限りません。

このページでは、Fetch Priority API と fetchpriority HTML 属性について説明します。この属性は、リソースの相対的な優先度(high または low)のヒントとして使用できます。Fetch Priority API は、Core Web Vitals の最適化に役立ちます。

まとめ

「Fetch Priority」は、次のような場面で役立ちます。

  • 画像要素に fetchpriority="high" を指定することで LCP 画像の優先度を上げ、LCP をより早く発生させます。
  • 現在最もよく使用されるハック(async スクリプトに <link rel="preload"> を挿入する)よりも優れたセマンティクスを使用して、async スクリプトの優先順位を上げます。
  • 後期スクリプトの優先順位を下げ、画像の順序付けを改善します。
Google フライトのホームページで 2 つのテストを比較したフィルムストリップ ビュー。一番下では、[フェッチの優先度] を使用してヒーロー画像の優先度を上げることで、LCP が 0.7 秒低下しています。
Google フライトのテストで、Largest Contentful Paint を 2.6 秒から 1.9 秒に改善する優先度をフェッチ。

これまで、デベロッパーがプリロード事前接続を使用して、リソースの優先度に影響を与えることはほとんどありませんでした。プリロードを使用すると、ブラウザが自然に検出する前に読み込む必要のある重要なリソースをブラウザに伝えることができます。これは特に、スタイルシートに含まれているフォント、背景画像、スクリプトから読み込まれるリソースなど、検出しにくいリソースに対して有効です。事前接続は、クロスオリジン サーバーへの接続をウォームアップし、最初のバイトまでの時間などの指標の改善に役立ちます。これは、送信元はわかっているが、必要となるリソースの正確な URL がわからない場合に便利です。

フェッチの優先度は、これらのリソースヒントを補完します。これはマークアップ ベースのシグナルで、fetchpriority 属性を通じて使用できます。デベロッパーは、この属性を使用して、特定のリソースの相対的な優先度を指定できます。また、JavaScript や Fetch API を通じて priority プロパティを使用してこれらのヒントを使用し、データに対して行われるリソース取得の優先度に影響を与えることもできます。フェッチ優先度はプリロードを補完することもできます。Largest Contentful Paint 画像を取得します。プリロードしても、優先度は低くなります。優先度の低い他のリソースによって差し戻された場合は、優先度フェッチを使用すると、画像が読み込まれるまでの時間を大幅に短縮できます。

リソースの優先度

リソースのダウンロード順序は、ページ上のすべてのリソースにブラウザに割り当てられた優先度によって異なります。優先度の計算ロジックに影響する可能性のある要素は次のとおりです。

  • リソースの種類(CSS、フォント、スクリプト、画像、サードパーティのリソースなど)。
  • ドキュメントがリソースを参照する場所または順序。
  • スクリプトで async 属性または defer 属性を使用するかどうか。

次の表に、Chrome でほとんどのリソースの優先度と順序がどのように設定されるかを示します。

  レイアウト ブロック フェーズで読み込む レイアウト ブロック フェーズで一度に 1 つずつ読み込む
点滅
優先
VeryHigh VeryLow
DevTools
優先
最高 最低
メインリソース
CSS(早期**) CSS(遅延**) CSS(メディアの不一致***)
スクリプト(早期** またはプリロード スキャナからではない) スクリプト(遅延**) スクリプト(非同期)
Font フォント(rel=preload)
インポート
画像(ビューポート内) 画像(最初の 5 個の画像 > 10,000px2) 画像
メディア(動画/音声)
プリフェッチ
XSL
XHR(同期) XHR/フェッチ*(非同期)

ブラウザは、同じ優先度でリソースを検出順にダウンロードします。ページの読み込み時にさまざまなリソースに割り当てられている優先度は、Chrome デベロッパー ツールの [ネットワーク] タブで確認できます。(テーブルの見出しを右クリックし、チェックボックスをオンにして、優先列を含めます)。

さまざまなフォント リソースがリストされている Chrome の DevTools の [Network] タブ。これらはすべて優先度が最も高くなります。
BBC ニュースの詳細ページにあるリソース type = "font" の優先度
さまざまなフォント リソースがリストされている Chrome の DevTools の [Network] タブ。優先度は「低」と「高」が混在しています。
BBC ニュースの詳細ページにあるリソース type = "script" の優先度。

優先度が変更されると、[大きなリクエスト行] の設定またはツールチップで、初期優先度と最終優先度の両方を確認できます。

Chrome の DevTools の [Network] タブ。[大きなリクエスト行] 設定がオンになっており、[優先度] 列に優先度が「高」で、その下に異なる初期優先度「中」の画像が表示されます。ツールチップに同じ内容が表示されます。
DevTools での優先順位の変更。

フェッチ優先度が必要になるのはどのような場合ですか。

ブラウザの優先順位付けのロジックについて理解したら、ページのダウンロード順序を調整して、パフォーマンスと Core Web Vitals を最適化できます。リソースのダウンロードの優先度に影響を与えるために変更できる項目の例をいくつか示します。

  • <script><link> などのリソースタグを、ブラウザでダウンロードする順序に配置します。通常、優先度が同じリソースは、検出された順に読み込まれます。
  • 必要なリソースを早期にダウンロードするには、preload のリソースヒントを使用します。これは、ブラウザが早い段階で検出するのが難しいリソースの場合は特に重要です。
  • async または defer を使用すると、他のリソースをブロックせずにスクリプトをダウンロードします。
  • スクロールしなければ見えない範囲のコンテンツを遅延読み込みして、ブラウザがより重要なスクロールせずに見える範囲のリソースに利用可能な帯域幅を使用できるようにする。

これらの手法は、ブラウザの優先度の計算を制御し、パフォーマンスと Core Web Vitals を改善するうえで役立ちます。たとえば、重要な背景画像がプリロードされている場合、その画像をはるかに早い段階で検出できるため、Largest Contentful Paint(LCP)が改善されます。

場合によっては、これらのハンドルではアプリケーションに最適なリソースに優先順位を付けるには不十分な場合があります。フェッチ優先度が役立つシナリオには、次のようなものがあります。

  • スクロールせずに見える範囲の画像がいくつかありますが、すべてに同じ優先度を設定する必要はありません。たとえば画像カルーセルでは、最初に表示される画像にのみ高い優先度を設定し、通常は最初に画面外に表示される他の画像の優先度を低く設定できます。
  • ビューポート内の画像は通常、優先度 Low から開始します。レイアウトが完成すると、Chrome はこれらの要素がビューポートにあることを検出し、優先度を上げます。これにより、通常、ヒーロー画像などの重要な画像の読み込みに大幅な遅延が発生します。マークアップでフェッチの優先度を指定すると、画像が High 優先度で開始され、ずっと早く読み込みを開始できます。これをいくぶん自動化するために、Chrome では最初の 5 つの大きな画像の優先度が Medium に設定されますが、明示的な fetchpriority="high" の方が効果的です。

    CSS の背景として含まれる LCP 画像を早期に検出するには、引き続きプリロードが必要です。背景画像の優先度を上げるには、プリロードに fetchpriority='high' を含めます。
  • スクリプトを async または defer として宣言すると、ブラウザはスクリプトを非同期で読み込むようになります。ただし、優先度の表に示すように、これらのスクリプトにも「低」優先度が割り当てられます。特にユーザー エクスペリエンスに不可欠なスクリプトの場合は、非同期ダウンロードを保証しながら優先度を上げることをおすすめします。
  • JavaScript fetch() API を使用してリソースやデータを非同期で取得する場合、ブラウザは優先度 High を割り当てます。特に、バックグラウンドの API 呼び出しとユーザー入力に応答する API 呼び出しが混在している場合、一部のフェッチを低い優先度で実行したほうがよい場合があります。バックグラウンド API 呼び出しの優先度を Low、インタラクティブな API 呼び出しの優先度を High に設定します。
  • ブラウザは CSS とフォントに High 優先度を割り当てますが、これらのリソースの中には他のリソースよりも重要なものもあります。フェッチの優先度を使用すると、重要性の低いリソースの優先度を下げることができます(初期の CSS はレンダリング ブロックを行うため、通常は優先度 High にします)。

fetchpriority 属性

link タグ、img タグ、script タグを使用してダウンロードする場合の、CSS、フォント、スクリプト、画像などのリソースタイプのダウンロード優先度を指定するには、fetchpriority HTML 属性を使用します。指定できる値は次のとおりです。

  • high: リソースの優先度は高く、ブラウザ独自のヒューリスティックがそれを妨げるわけではない限り、優先度を通常よりも高くする必要があります。
  • low: リソースは優先度が低いため、ヒューリスティックに許容される場合、ブラウザで優先度を下げます。
  • auto: ブラウザが適切な優先度を選択できるようにするデフォルト値。

マークアップで fetchpriority 属性と、スクリプトで同等の priority プロパティを使用する例をいくつか示します。

<!-- We don't want a high priority for this above-the-fold image -->
<img src="/images/in_viewport_but_not_important.svg" fetchpriority="low" alt="I'm an unimportant image!">

<!-- We want to initiate an early fetch for a resource, but also deprioritize it -->
<link rel="preload" href="/js/script.js" as="script" fetchpriority="low">

<script>
  fetch('https://example.com/', {priority: 'low'})
  .then(data => {
    // Trigger a low priority fetch
  });
</script>

ブラウザの優先順位と fetchpriority の影響

次の表に示すように、さまざまなリソースに fetchpriority 属性を適用して、計算された優先度を増減できます。各行の fetchpriority="auto"(◉)は、そのタイプのリソースのデフォルトの優先度を示します。(Google ドキュメントとしても入手できます)。

  レイアウト ブロック フェーズで読み込む レイアウト ブロック フェーズで一度に 1 つずつ読み込む
点滅
優先
VeryHigh VeryLow
DevTools
優先
最高 最低
メインリソース
CSS(早期**) ⬆◉
CSS(遅延**)
CSS(メディアの不一致***) ⬆*** ◉⬇
スクリプト(早期** またはプリロード スキャナからではない) ⬆◉
スクリプト(遅延**)
スクリプト(async/defer) ◉⬇
Font
フォント(rel=preload) ⬆◉
インポート
画像(ビューポート内 - レイアウト後) ⬆◉
画像(最初の 5 個の画像 > 10,000px2)
画像 ◉⬇
メディア(動画/音声)
XHR(同期)- サポート終了
XHR/フェッチ*(非同期) ⬆◉
プリフェッチ
XSL

fetchpriority は、相対優先度を設定します。つまり、優先度を明示的に High または Low に設定するのではなく、デフォルトの優先度を適切な量だけ増減します。多くの場合、優先度は High または Low になりますが、常にそうなるとは限りません。たとえば、fetchpriority="high" を持つクリティカルな CSS の優先度は「非常に高い」/「最高」のままであり、これらの要素に fetchpriority="low" を使用しても「高」の優先度が維持されます。どちらの場合も、優先度を High または Low に明示的に設定する必要はありません。

ユースケース

fetchpriority 属性は、リソースを取得する優先度についてブラウザに追加的なヒントを提供する場合に使用します。

LCP イメージの優先度を上げる

fetchpriority="high" を指定すると、LCP などの重要なイメージの優先度を高めることができます。

<img src="lcp-image.jpg" fetchpriority="high">

次の比較は、Google フライトページで LCP の背景画像が読み込まれた状態(取得優先度ありとなしの場合)を示しています。優先度を「高」に設定すると、LCP は 2.6 秒から 1.9 秒に向上しました。

Cloudflare ワーカーを使用し、優先度フェッチを使用して Google フライトのページを書き換えるテスト。

fetchpriority="low" を使用して、すぐに重要ではないスクロールせずに見える範囲の画像(画像カルーセルのオフスクリーン画像など)の優先度を下げます。

<ul class="carousel">
  <img src="img/carousel-1.jpg" fetchpriority="high">
  <img src="img/carousel-2.jpg" fetchpriority="low">
  <img src="img/carousel-3.jpg" fetchpriority="low">
  <img src="img/carousel-4.jpg" fetchpriority="low">
</ul>

画像 2 ~ 4 はビューポートの外側に表示されますが、high に引き上げられるほど「近い」と見なされ、load=lazy 属性が追加されていても読み込まれます。そのため、fetchpriority="low" が適切なソリューションです。

Oodle アプリを使用した以前のテストでは、これを使用して、読み込み時に表示されない画像の優先度を低くしました。ページの読み込み時間が 2 秒短縮されました。

Oodle アプリの画像カルーセルで使用されている場合のフェッチ優先度の比較。左側では、ブラウザがカルーセル画像にデフォルトの優先順位を設定していますが、右側の例よりも画像のダウンロードと描画が約 2 秒遅くなります。つまり、最初のカルーセル画像だけに高い優先度が設定されています。
最初のカルーセル画像だけの優先度を高くすると、ページの読み込みが速くなります。

プリロード リソースの優先度を下げる

プリロードされたリソースが他の重要なリソースと競合しないようにするには、リソースの優先順位を下げることができます。この方法は、画像、スクリプト、CSS に使用します。

<!-- Lower priority only for non-critical preloaded scripts -->
<link rel="preload" as="script" href="critical-script.js">
<link rel="preload" as="script" href="non-critical-script.js" fetchpriority="low">

<!-- Preload CSS without blocking render, or other resources -->
<link rel="preload" as="style" href="theme.css" fetchpriority="low" onload="this.rel='stylesheet'">

スクリプトの優先度を再設定する

ページをインタラクティブにする必要があるスクリプトは、すばやく読み込む必要がありますが、より重要なレンダリング ブロック リソースをブロックしないようにする必要があります。これらには、優先度の高い async のマークを付けることができます。

<script src="async_but_important.js" async fetchpriority="high"></script>

特定の DOM 状態に依存している場合は、スクリプトを async としてマークすることはできません。ただし、広告がページの後半で実行される場合は、優先度を低くして読み込むことができます。

<script src="blocking_but_unimportant.js" fetchpriority="low"></script>

これにより、このスクリプトに到達するとパーサーはブロックされますが、それ以前のコンテンツが優先されるようになります。

完成した DOM が必要な場合は、代わりに defer 属性(DOMContentLoaded の後に順番に実行)を使用するか、ページの下部で async を使用します。

重要性の低いデータ取得の優先度を下げる

ブラウザが高い優先度で fetch を実行する。複数の取得が同時に実行される可能性がある場合は、重要度の高いデータ取得に高いデフォルトの優先度を使用し、重要度の低いデータの優先度を下げることができます。

// Important validation data (high by default)
let authenticate = await fetch('/user');

// Less important content data (suggested low)
let suggestedContent = await fetch('/content/suggested', {priority: 'low'});

優先度の実装メモを取得する

取得優先度を使用すると、特定のユースケースでパフォーマンスを向上させることができますが、取得優先度を使用する際は次の点に注意してください。

  • fetchpriority 属性はディレクティブではなくヒントです。ブラウザはデベロッパーの設定を優先しようとしますが、リソースの優先度の設定を適用して競合を解決することもできます。
  • 「Fetch Priority」と「プリロード」を混同しないでください。

    • プリロードは必須のフェッチであり、ヒントではありません。
    • プリロードを行うと、ブラウザはリソースを早期に検出できますが、デフォルトの優先度でリソースを取得することに変わりはありません。逆に、フェッチの優先度は見つけやすさには役立ちませんが、フェッチの優先度の増減はできます。
    • 多くの場合、優先度の変更による影響よりも、プリロードによる影響を観察、測定する方が簡単です。

    フェッチの優先度は、優先順位の粒度を上げることで、プリロードを補完します。プリロードを LCP 画像の <head> の最初の項目の 1 つとしてすでに指定している場合は、high 取得優先度によって LCP が大幅に改善されない可能性があります。ただし、他のリソースの読み込み後にプリロードが行われる場合は、high フェッチの優先度により LCP を改善できます。重要な画像が CSS の背景画像の場合は、fetchpriority = "high" を使用してプリロードします。

  • 優先順位付けによる読み込み時間の改善は、使用可能なネットワーク帯域幅をめぐってより多くのリソースが競合する環境ではより重要になります。これは、並列ダウンロードができない HTTP/1.x 接続、または低帯域幅の HTTP/2 または HTTP/3 接続で一般的です。このような場合、優先順位を付けることでボトルネックを解決できます。

  • CDN は一律に HTTP/2 の優先順位を実装しません。HTTP/3 の場合も同様です。ブラウザがフェッチ優先度から優先度を伝達しても、CDN は指定された順序でリソースの優先順位を変更しないことがあります。このため、フェッチ優先度のテストが困難になります。優先度は、ブラウザ内で内部的にも、優先度設定をサポートするプロトコル(HTTP/2 と HTTP/3)でも適用されます。CDN や送信元のサポートとは無関係に、ブラウザがリソースをリクエストすると優先度が変わることが多いため、フェッチ優先度は、CDN や送信元のサポートとは無関係に、内部のブラウザの優先度を判断するためだけに使用する価値があります。たとえば、ブラウザが重要な <head> アイテムを処理する間、画像など優先度の低いリソースはリクエストされないことがよくあります。

  • 最初の設計では、フェッチ優先度をベスト プラクティスとして導入できない場合があります。開発サイクルの後半で、ページ上のさまざまなリソースに優先度を割り当てることができます。優先度が想定と一致しない場合は、フェッチ優先度を導入してさらに最適化できます。

デベロッパーは、パーサーによって検出されないリソース(フォント、インポート、バックグラウンド LCP 画像)をプリロードするために、本来の目的でプリロードを使用する必要があります。preload ヒントの配置は、リソースがプリロードされるタイミングに影響します。

フェッチ優先度とは、リソースの取得時にリソースをどのようにフェッチすべきかに関するものです。

プリロードの使用に関するヒント

プリロードを使用する場合は、次の点に注意してください。

  • HTTP ヘッダーにプリロードを含めると、そのプリロードが読み込み順序の他のすべてのものよりも前に配置されます。
  • 一般的に、優先度が Medium 以上の場合は、パーサーが到達順に読み込みます。HTML の先頭にプリロードを含める場合は注意が必要です。
  • フォント プリロードは、通常、head の終端または body の始めに行くと最も効果を発揮します。
  • インポートのプリロード(動的 import() または modulepreload)は、インポートが必要なスクリプトタグの後に実行する必要があります。そのため、依存関係の読み込み中にスクリプトを評価できるように、まずスクリプトの読み込みまたは解析を行ってください。
  • イメージのプリロードには、デフォルトで Low または Medium の優先度が設定されています。非同期スクリプトやその他の優先度の低いタグまたは最も低いタグに対して、相対的な順序で並べます。

History

Fetch Priority は、2018 年に Chrome のオリジン トライアルとして最初にテストされ、2021 年に importance 属性を使用して再度テストされました。当時、これは優先度のヒントと呼ばれていました。その後、ウェブ標準プロセスの一環として、HTML では fetchpriority、JavaScript の Fetch API では priority にインターフェースが変更されました。混乱を避けるために、今後はこの API 取得優先度をこの API 取得の優先度と呼ぶことにします。

おわりに

プリロード動作の修正や最近の Core Web Vitals と LCP への注力により、開発者はフェッチ 優先度に関心を持つ可能性が高いと思われます。好みの読み込みシーケンスを実現するための追加のノブを利用できるようになりました。