ナビゲーションをスキップ
部 IV 章 19

リソースヒント

Hero image of Web Almanac characters lining up to HTML, JavaScript, and image resources in a line on the way to a web page.

序章

リソースヒント は、どのようなリソースがすぐに必要になるかについての「ヒント」をブラウザに提供します。このヒントを受け取った結果としてブラウザが取るアクションは、リソースヒントの種類によって異なります。リソースヒントは正しく使用されると、重要なアクションを先取りすることでページのパフォーマンスを向上させることができます。

は、リソースヒントの結果としてパフォーマンスが向上しています。

  • Jabongは、重要なスクリプトをプリロードすることで、対話までの時間を1.5秒短縮しました。
  • Barefoot Wineは、目に見えるリンクを先読みすることで、将来のページの対話までの時間を2.7秒短縮しました。
  • Chrome.comは、クリティカルなオリジンに事前接続することで、待ち時間を0.7秒短縮しました。

今日、ほとんどのブラウザでサポートされているリソースヒントには、4つの独立したものがあります。dns-prefetch, preconnect, preload, prefetch です。

dns-prefetch

dns-prefetchの役割は、初期のDNS検索を開始することである。サードパーティのDNSルックアップを完了させるのに便利です。たとえば、CDN、フォントプロバイダー、サードパーティAPIのDNSルックアップなどです。

preconnect

preconnectは、DNSルックアップ、TCPハンドシェイク、TLSネゴシエーションを含む早期接続を開始します。このヒントはサードパーティとの接続を設定する際に有用である。preconnectの用途はdns-prefetchの用途と非常によく似ているが、preconnectはブラウザのサポートが少ない。しかし、IE 11のサポートを必要としないのであれば、preconnectの方が良い選択であろう。

preload

preloadヒントは、早期のリクエストを開始します。これは、パーサによって発見されるのが遅れてしまうような重要なリソースをロードするのに便利です。たとえば、ブラウザがスタイルシートを受信し解析したあとでしか重要な画像を発見できない場合、画像をプリロードすることは意味があるかもしれません。

prefetch

prefetchは優先度の低いリクエストを開始します。これは、次の(現在のページではなく)ページの読み込みで使われるであろうリソースを読み込むのに便利です。プリフェッチの一般的な使い方は、アプリケーションが次のページロードで使われると「予測」したリソースをロードすることです。これらの予測は、ユーザーのマウスの動きや、一般的なユーザーの流れ/旅のようなシグナルに基づいているかもしれません。

文法

リソースヒント使用率の97%は、リソースヒントを指定するために<link>タグを使用しています。たとえば、以下のようになります。

<link rel="prefetch" href="shopping-cart.js">

リソースヒント使用率のわずか3%は、リソースヒントの指定にHTTPヘッダを使用しました。たとえば、以下のようになります。

Link: <https://example.com/shopping-cart.js>; rel=prefetch

HTTPヘッダー内のリソースヒントの使用量が非常に少ないため、本章の残りの部分では、<link>タグと組み合わせたリソースヒントの使用量の分析のみに焦点を当てています。しかし、今後、HTTP/2 Pushが採用されるようになると、HTTPヘッダーでのリソースヒントの使用量が増える可能性のあることは注目に値します。これは、HTTP/2 Pushがリソースをプッシュするためのシグナルとして、HTTPのプリロード Link ヘッダーを再利用していることに起因しています。

リソースヒント

注: モバイルとデスクトップでは、リソースヒントの利用パターンに目立った違いはありませんでした。そのため、簡潔にするために、本章ではモバイルの統計のみを掲載しています。

リソースヒント 利用状況(サイトの割合)
dns-prefetch 29%
preload 16%
preconnect 4%
prefetch 3%
prerender (非推奨) 0.13%
図19.1. リソースヒントの採用。

dns-prefetchの相対的な人気は驚くに値しません。これはよく知られたAPIであり(2009ではじめて登場しました)、すべての主要なブラウザでサポートされており、すべてのリソースヒントの中でもっとも「安価」なものです。dns-prefetchはDNSの検索を行うだけなので、データの消費量が非常に少なく、使用する上でのデメリットはほとんどありません。dns-prefetchはレイテンシの高い状況でもっとも有用である。

つまり、IE11以下をサポートする必要がないサイトであれば、dns-prefetchからpreconnectに切り替えるのが良いでしょう。HTTPSがユビキタスな時代には、preconnectは安価でありながら、より大きなパフォーマンスの向上をもたらします。dns-prefetchとは異なり、preconnectはDNSの検索だけでなく、TCPハンドシェイクとTLSネゴシエーションも開始することに注意してください。証明書チェーンはTLSネゴシエーション中にダウンロードされるが、これには通常数キロバイトのコストがかかります。

prefetchは3%のサイトで利用されており、もっとも広く利用されていないリソースヒントである。この使用率の低さは、prefetchが現在のページの読み込みよりも後続のページの読み込みを改善するのに有用であるという事実によって説明できるかもしれません。したがって、ランディングページの改善や最初に閲覧されたページのパフォーマンスを向上させることだけに焦点を当てているサイトでは、これは見過ごされてしまうだろう。

リソースヒント ページごとのリソースヒント
中央値
ページごとのリソースヒント
90パーセンタイル
dns-prefetch 2 8
preload 2 4
preconnect 2 8
prefetch 1 3
prerender (非推奨) 1 1
図19.2. そのリソースヒントを使用している全ページのうち、1ページあたりに使用されているリソースヒントの数の中央値と90パーセンタイル。

リソースヒントは、選択的に使用されるときにもっとも効果的です(“すべてが重要なときには、何も重要ではない”)。上の図19.2は、少なくとも1つのリソースヒントを使用しているページの1ページあたりのリソースヒントの数を示しています。適切なリソースヒントの数を定義する明確なルールはありませんが、ほとんどのサイトが適切にリソースヒントを使用しているように見えます。

crossorigin属性

ウェブ上に取り込まれるほとんどの「伝統的な」リソース(imagesstylesheetsscript)は、クロスオリジンリソース共有(CORS)を選択せずに取り込まれています。つまり、これらのリソースがクロスオリジンサーバーからフェッチされた場合、デフォルトでは同一オリジンポリシーのために、その内容をページで読み返すことができないということです。

場合によっては、ページはコンテンツを読む必要がある場合、CORSを使用してリソースを取得するようにオプトインできます。CORSは、ブラウザが「許可を求める」ことを可能にし、それらのクロスオリジンリソースへのアクセスを取得します。

新しいリソースタイプ(フォント、fetch() リクエスト、ESモジュールなど)では、ブラウザはデフォルトでCORSを使用してリソースをリクエストし、サーバーがアクセス許可を与えていない場合はリクエストを完全に失敗させます。

クロスオリジン 使用方法 説明
未設定 92% crossorigin属性がない場合、リクエストはシングルオリジンポリシーに従います。
anonymous(に相当する) 7% クレデンシャルを含まないクロスオリジンリクエストを実行します。
use-credentials 0.47% クレデンシャルを含むクロスオリジンリクエストを実行します。
図19.3. リソースヒントインスタンスの割合としての クロスオリジン 属性の採用。

リソースヒントのコンテキストでは、crossorigin属性を使用することで、マッチすることになっているリソースのCORSモードにマッチし、リクエストに含めるべき資格情報を示すことができます。たとえば、anonymousはCORSを有効にし、クロスオリジンリクエストには資格情報を含めるべきではないことを示します。

<link rel="prefetch" href="https://other-server.com/shopping-cart.css" crossorigin="anonymous">

他のHTML要素はcrossorigin属性をサポートしていますが、この分析では、リソースヒントを使った使用法のみを見ています。

as属性

aspreloadリソースヒントと一緒に使用されるべき属性で、要求されたリソースの種類(画像、スクリプト、スタイルなど)をブラウザに知らせるため使用されます。これにより、ブラウザがリクエストに正しく優先順位をつけ、正しいコンテンツセキュリティポリシー(CSP)を適用するのに役立ちます。CSPはHTTPヘッダーで表現されるセキュリティメカニズムです、信頼できるソースのセーフリストを宣言することで、XSSやその他の悪意のある攻撃の影響を緩和するのに役立ちます。

88%
図19.4. as 属性を使用したリソースヒントインスタンスの割合。

リソースヒントインスタンスの88%はas属性を使用しています。asが指定されている場合、圧倒的にスクリプトに使われています。92%がスクリプト、3%がフォント、3%がスタイルです。これはスクリプトがほとんどのサイトのアーキテクチャで重要な役割を果たしていることと、スクリプトが攻撃のベクターとして使用される頻度が高いことを考えると当然のことです(したがって、スクリプトが正しいCSPを適用されることがとくに重要です)。

将来のこと

現時点では、現在のリソースヒントのセットを拡張する提案はありません。しかし、優先度ヒントとネイティブの遅延ローディングは、ローディングプロセスを最適化するためのAPIを提供するという点で、リソースヒントに似た精神を持つ2つの技術が提案されています。

優先順位のヒント

優先度ヒントは、リソースのフェッチの優先度をhigh,low,autoのいずれかで表現するためのAPIです。これらは幅広いHTMLタグで利用できます。とくに<image>,<link>,<script>,<iframe>などです。

<carousel>
  <img src="cat1.jpg" importance="high">
  <img src="cat2.jpg" importance="low">
  <img src="cat3.jpg" importance="low">
</carousel>
図19.4. 画像のカルーセルで優先度ヒントを使用するHTMLの例。

たとえば、画像カルーセルがある場合、優先度ヒントを使用して、ユーザーがすぐに見る画像に優先順位をつけ、後の画像に優先順位をつけることができます。

0.04%
図19.5. 優先ヒントの採用率。

優先度ヒントは実装されており、Chromiumブラウザのバージョン70以降では機能フラグを使ってテストできます。まだ実験的な技術であることを考えると、0.04%のサイトでしか使用されていないのは当然のことです。

優先度ヒントの85%は<img>タグを使用しています。優先度ヒントはほとんどがリソースの優先順位を下げるために使われます。使用率の72%はimportance="low"で、28%はimportance="high"です。

ネイティブの遅延ローディング

ネイティブの遅延ローディングは、画面外の画像やiframeの読み込みを遅延させるためのネイティブAPIです。これにより、最初のページ読み込み時にリソースを解放し、使用されないアセットの読み込みを回避できます。以前は、この技術はサードパーティのJavaScriptライブラリでしか実現できませんでした。

ネイティブな遅延読み込みのためのAPIはこのようになります。<img src="cat.jpg" loading="lazy">.

ネイティブな遅延ローディングは、Chromium76以上をベースにしたブラウザで利用可能です。このAPIは発表が遅すぎて今年のWeb Almanacのデータセットには含まれていませんが、来年に向けて注目しておきたいものです。

結論

全体的に、このデータはリソースヒントをさらに採用する余地があることを示唆しているように思われる。ほとんどのサイトでは、dns-prefetchからpreconnectに切り替えることで恩恵を受けることができるだろう。もっと小さなサブセットのサイトでは、prefetchpreloadを採用することで恩恵を受けることができるだろう。prefetchpreloadをうまく使うには、より大きなニュアンスがあり、それが採用をある程度制限していますが、潜在的な利益はより大きくなります。HTTP/2 Pushや機械学習技術の成熟により、preloadprefetchの採用が増える可能性もあります。

著者

引用

BibTeX
@inbook{WebAlmanac.2019.リソースヒント,
author = "Hempenius、KatieとDavies、AndyとPollard、BarryとWeiss、YoavとViscomi、Rick",
title = "リソースヒント",
booktitle = "2019 Web Almanac",
chapter = 19,
publisher = "HTTP Archive",
year = "2019",
language = "日本語",
url = "https://almanac.httparchive.org/en/2019/resource-hints"
}