キャッシュ ストレージは強力なツールです。アプリがネットワーク状態の影響を受けにくくなります。キャッシュをうまく活用すると、ネットワーク状態にかかわらず、ウェブアプリをオフラインで使用可能にして、可能な限り高速にアセットを配信できます。アセットとデータで説明したように、必要なアセットのキャッシュに最適な戦略を決定できます。キャッシュを管理するために、Service Worker は Cache Storage API を使用します。
対応ブラウザ
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
Cache Storage API は、さまざまなコンテキストで使用できます。
- ウィンドウ コンテキスト(PWA のメインスレッド)。
- Service Worker。
- 使用しているその他のワーカー。
Service Worker を使用してキャッシュを管理するメリットの 1 つは、そのライフサイクルがウィンドウに関連付けられていないことです。つまり、メインスレッドをブロックしないということです。Cache Storage API を使用するには、これらのコンテキストのほとんどを TLS 接続の下に置く必要があります。
キャッシュに保存するデータ
キャッシュについて最初に疑問に思われるのは、何をキャッシュに保存するかです。この問いに対する唯一の答えはありませんが、ユーザー インターフェースをレンダリングするために必要なすべての最小限のリソースから始めることができます。
これらのリソースには次のものが含まれます。
- メインページの HTML(アプリの start_url)。
- メインのユーザー インターフェースに必要な CSS スタイルシート。
- ユーザー インターフェースで使用される画像。
- ユーザー インターフェースの表示に必要な JavaScript ファイル。
- 基本的なエクスペリエンスを表示するために必要なデータ(JSON ファイルなど)。
- ウェブフォント。
- 複数ページ アプリケーションで、他の HTML ドキュメントをすばやく、またはオフラインで配信したい。
オフライン対応
オフライン対応はプログレッシブ ウェブアプリの要件の 1 つですが、クラウドゲーム ソリューションや暗号資産アプリなど、すべての PWA に完全なオフライン エクスペリエンスは必要ありません。そのため、このような状況でユーザーをガイドする基本的なユーザー インターフェースを提供しても問題ありません。
ウェブ レンダリング エンジンがページを読み込めなかったことを示すブラウザのエラー メッセージが PWA でレンダリングされないようにする必要があります。代わりに Service Worker を使用して独自のメッセージを表示することで、一般的で混乱を招くブラウザエラーを回避できます。
PWA のニーズに応じて、さまざまなキャッシュ戦略を使用できます。そのため、高速で信頼性の高いエクスペリエンスを提供するようにキャッシュの使用を設計することが重要です。たとえば、すべてのアプリアセットが高速でダウンロードされ、容量をあまり消費せず、リクエストごとに更新する必要がない場合は、すべてのアセットをキャッシュに保存するのが有効な戦略です。一方、最新バージョンである必要があるリソースがある場合は、それらのアセットをまったくキャッシュに保存しないことを検討できます。
API の使用
Cache Storage API を使用して、配信元内で一連のキャッシュを定義します。各キャッシュは、定義可能な文字列名で識別できます。caches
オブジェクトを使用して API にアクセスします。open
メソッドにより、作成済みのキャッシュの作成、または作成が可能になります。open メソッドは、キャッシュ オブジェクトに対する Promise を返します。
caches.open("pwa-assets")
.then(cache => {
// you can download and store, delete or update resources with cache arguments
});
アセットのダウンロードと保存
アセットのダウンロードと保存をブラウザに要求するには、add
メソッドまたは addAll
メソッドを使用します。add
メソッドはリクエストを作成して 1 つの HTTP レスポンスを格納し、addAll
はリクエストまたは URL の配列に基づくトランザクションとして HTTP レスポンスのグループを格納します。
caches.open("pwa-assets")
.then(cache => {
cache.add("styles.css"); // it stores only one resource
cache.addAll(["styles.css", "app.js"]); // it stores two resources
});
キャッシュ ストレージ インターフェースには、すべてのヘッダーと本文を含むレスポンス全体が保存されます。そのため、HTTP リクエストまたは URL をキーとして使用して、後で取得することができます。その方法については、サービングの章をご覧ください。
キャッシュに保存するタイミング
PWA では、ファイルをキャッシュに保存するタイミングを決定します。1 つの方法は、Service Worker のインストール時にできるだけ多くのアセットを保存することですが、通常はおすすめしません。不要なリソースをキャッシュに保存すると、帯域幅と保存容量が浪費され、アプリが意図しない古いリソースを提供する原因となる可能性があります。
すべてのアセットを一度にキャッシュする必要はありません。次のように、PWA のライフサイクル中に何度でもキャッシュできます。
- Service Worker のインストール時。
- 最初のページが読み込まれた後。
- ユーザーが特定のセクションまたはルートに移動したとき。
- ネットワークがアイドル状態のとき。
新しいファイルのキャッシュ保存は、メインスレッド内または Service Worker コンテキスト内でリクエストできます。
Service Worker でのアセットのキャッシュ保存
最も一般的なシナリオの 1 つは、Service Worker のインストール時に、最小限のアセットのセットをキャッシュに保存することです。そのためには、Service Worker の install
イベント内でキャッシュ ストレージ インターフェースを使用します。
Service Worker スレッドはいつでも停止できるため、addAll
Promise が完了するまでブラウザに待機するようブラウザにリクエストできます。これにより、すべてのアセットが保存され、アプリの一貫性が保たれる可能性が高まります。次の例は、Service Worker のイベント リスナーで受け取ったイベント引数の waitUntil
メソッドを使用して、これを行う方法を示しています。
const urlsToCache = ["/", "app.js", "styles.css", "logo.svg"];
self.addEventListener("install", event => {
event.waitUntil(
caches.open("pwa-assets")
.then(cache => {
return cache.addAll(urlsToCache);
});
);
});
waitUntil()
メソッドは Promise を受け取り、Promise 内のタスクが解決(完了または失敗)されるのを待ってから、Service Worker プロセスを終了するようブラウザに指示します。単一の結果が waitUntil()
メソッドに渡されるように、Promise を連結して add()
または addAll()
の呼び出しを返すことが必要な場合があります。
async/await 構文を使用して Promise を処理することもできます。その場合は、次の例のように、await
を呼び出せる非同期関数を作成し、呼び出し後に Promise を waitUntil()
に返す必要があります。
const urlsToCache = ["/", "app.js", "styles.css", "logo.svg"];
self.addEventListener("install", (event) => {
let cacheUrls = async () => {
const cache = await caches.open("pwa-assets");
return cache.addAll(urlsToCache);
};
event.waitUntil(cacheUrls());
});
クロスドメインのリクエストと不透明なレスポンス
PWA は、配信元およびクロスドメインのアセット(サードパーティの CDN のコンテンツなど)をダウンロードしてキャッシュに保存できます。クロスドメイン アプリの場合、キャッシュの操作は同一オリジンのリクエストと非常によく似ています。リクエストが実行され、レスポンスのコピーがキャッシュに保存されます。キャッシュに保存された他のアセットと同様に、アプリのオリジンでのみ使用できます。
アセットは不透明なレスポンスとして保存されます。つまり、コードはそのレスポンスのコンテンツやヘッダーを表示または変更できません。また、不透明なレスポンスは実際のサイズが Storage API で公開されず、割り当てに影響します。一部のブラウザでは、ファイルが 1 KB であっても、7 MB などの大きなサイズが公開されています。
アセットの更新と削除
cache.put(request, response)
を使用してアセットを更新し、delete(request)
でアセットを削除できます。
詳しくは、Cache オブジェクトのドキュメントをご覧ください。
キャッシュ ストレージのデバッグ
多くのブラウザには、DevTools の [Application] タブ内でキャッシュ ストレージの内容をデバッグする手段が用意されています。ここでは、現在の送信元内のすべてのキャッシュの内容を確認できます。これらのツールについては、ツールとデバッグの章で詳しく説明します。