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

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

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

対応ブラウザ

  • Chrome: 102。
  • Edge: 102.
  • Firefox: 132。
  • Safari: 17.2。

ソース

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

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

概要

優先取得が役立つ主な分野は次のとおりです。

  • 画像要素に fetchpriority="high" を指定して LCP 画像の優先度を高め、LCP をより早く発生させる。
  • async スクリプトの優先度を上げ、現在の最も一般的なハック(async スクリプトに <link rel="preload"> を挿入する)よりも優れたセマンティクスを使用。
  • ボディの末尾のスクリプトの優先度を下げて、画像とのシーケンスが改善されるようにしました。
Google フライトのホームページの 2 つのテストを比較したフィルムストリップ ビュー。下部では、取得優先度を使用してヒーロー画像の優先度を高め、LCP を 0.7 秒短縮しています。
Google フライトのテストで、取得優先度を変更した結果、Largest Contentful Paint が 2.6 秒から 1.9 秒に短縮されました。

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

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

リソースの優先度

リソースのダウンロード順序は、ページ上のすべてのリソースにブラウザが割り当てた優先度によって異なります。優先度計算ロジックに影響する要因には、次のようなものがあります。

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

次の表に、Chrome がほとんどのリソースを優先順位付けして順序付けする方法を示します。

  レイアウト ブロック フェーズで読み込む レイアウト ブロッキング フェーズで 1 つずつ読み込む
Blink
優先度
VeryHigh VeryLow
DevTools
の優先度
最高
メイン リソース
CSS(早期**) CSS(遅れ**) CSS(メディアの不一致***)
スクリプト(早期** またはプリロード スキャナ以外) スクリプト(遅れ**) スクリプト(非同期)
フォント フォント(rel=preload)
インポート
画像(ビューポート内) 画像(最初の 5 枚の画像が 10,000 px2 を超える場合) 画像
メディア(動画/音声)
プリフェッチ
XSL
XHR(同期) XHR/フェッチ*(非同期)

ブラウザは、同じ優先度が計算されたリソースを検出順にダウンロードします。ページの読み込み時にさまざまなリソースに割り当てられた優先度を確認するには、Chrome DevTools の [ネットワーク] タブを使用します。(テーブルの見出しを右クリックして、[優先度] 列をオンにしてください)。

多数のフォント リソースがリストされている Chrome デベロッパー ツールの [Network] タブ。すべて優先度が最も高いです。
BBC ニュースの詳細ページのリソース type = "font" の優先度
多数のフォント リソースがリストされている Chrome デベロッパー ツールの [Network] タブ。優先度は低いものと高いものが混在しています。
BBC ニュースの詳細ページのリソース type = "script" の優先度

優先度が変更されると、[Big request rows] 設定またはツールチップに、最初の優先度と最終的な優先度の両方が表示されます。

Chrome の DevTools の [Network] タブ。[Big request rows] の設定がオンになっていて、[Priority] 列に、優先度が「高」の最初の画像と、優先度が「中」の別の初期画像が表示されています。ツールチップにも同じことが表示されます。
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 属性

fetchpriority HTML 属性を使用すると、linkimgscript タグを使用してダウンロードする CSS、フォント、スクリプト、画像などのリソースタイプのダウンロード優先度を指定できます。次の値が設定されます。

  • 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 つずつ読み込む
Blink
優先度
VeryHigh VeryLow
DevTools
の優先度
最高
メイン リソース
CSS(早期**) ⬆◉
CSS(遅れ**)
CSS(メディアの不一致***) ⬆*** ◉⬇
スクリプト(早期** またはプリロード スキャナ以外) ⬆◉
スクリプト(遅れ**)
スクリプト(非同期/遅延) ◉⬇
フォント
フォント(rel=preload) ⬆◉
インポート
画像(ビューポート内 - レイアウト後) ⬆◉
画像(最初の 5 枚の画像が 10,000 px2 を超えている場合)
画像 ◉⬇
メディア(動画/音声)
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">

次の比較は、フェッチ優先度ありとなしの場合の、LCP の背景画像が読み込まれた Google フライト ページを示しています。優先度を高に設定すると、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 属性はディレクティブではなくヒントです。ブラウザはデベロッパーの設定を尊重しようとしますが、リソースの優先度にリソースの優先度設定を適用して競合を解決することもできます。
  • 取得優先度とプリロードを混同しないでください。

    • プリロードはヒントではなく、必須の取得です。
    • プリロードを使用すると、ブラウザはリソースを早期に検出できますが、リソースはデフォルトの優先度でフェッチされます。一方、取得優先度は発見可能性には影響しませんが、取得優先度の増減は可能です。
    • 優先度の変更の影響よりも、プリロードの影響を観察して測定できる場合が多いです。

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

  • 優先順位付けによる読み込み時間の短縮は、利用可能なネットワーク帯域幅を複数のリソースが競合している環境で効果的です。これは、並列ダウンロードが不可能な HTTP/1.x 接続や、低帯域幅の HTTP/2 接続または HTTP/3 接続でよく見られます。このような場合は、優先順位付けによってボトルネックを解消できます。

  • CDN は、HTTP/2 の優先度付けを統一的に実装していません。HTTP/3 についても同様です。ブラウザが Fetch Priority から優先度を通知しても、CDN が指定された順序でリソースの優先度を変更しない場合があります。そのため、取得優先度のテストは困難です。優先度は、ブラウザ内部と、優先度付けをサポートするプロトコル(HTTP/2 と HTTP/3)の両方で適用されます。ブラウザがリソースをリクエストするときに優先度が頻繁に変更されるため、CDN やオリジンのサポートに関係なく、内部ブラウザの優先度付けにのみ取得優先度を使用する価値はあります。たとえば、ブラウザが重要な <head> アイテムを処理している間、画像などの優先度の低いリソースはリクエストされません。

  • 初期設計では、ベスト プラクティスとして取得優先度を導入できない場合があります。開発サイクルの後半で、ページ上のさまざまなリソースに割り当てられた優先度を確認できます。期待どおりにない場合は、取得優先度を導入してさらに最適化できます。

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

取得優先度は、リソースの取得方法に関するものです。

プリロードを使用する際のヒント

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

  • HTTP ヘッダーにプリロードを含めると、読み込み順序で他のすべての前にプリロードが配置されます。
  • 通常、プリロードは、Medium 以上の優先度を持つものについては、パーサーが取得する順序で読み込まれます。HTML の先頭にプリロードを含める場合は注意が必要です。
  • フォント プリロードは、ヘッダーの末尾または本文の先頭に配置するのが適切です。
  • インポート プリロード(動的 import() または modulepreload)は、インポートを必要とするスクリプトタグの後に実行されるため、スクリプトが最初に読み込まれるか解析されるようにし、依存関係の読み込み中に評価できるようにします。
  • 画像プリロードのデフォルトの優先度は Low または Medium です。非同期スクリプトや優先度の低いタグと比較して順序付けます。

履歴

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

まとめ

デベロッパーは、プリロード動作の修正と最近の Core Web Vitals と LCP への注目により、取得優先度に関心を持つ可能性があります。好みの読み込み順序を実現するためのノブが追加されました。