これまでは、インフラストラクチャのメンションや、コード スニペットの
Cache
インターフェース。
Service Worker を効果的に使用するには、1 つ以上のキャッシュ戦略、
Cache
インターフェースの知識が少し必要になります。
キャッシュ戦略は、Service Worker の fetch
イベントと Cache
インターフェース間のインタラクションです。
キャッシュ戦略の記述方法は、
たとえば、静的アセットのリクエストをドキュメントとは異なる方法で処理することが望ましい場合があります。
これはキャッシュ戦略の構成方法にも影響します。
戦略そのものに入る前に
次に、Cache
インターフェースがどういうものとは何か、
Service Worker のキャッシュを管理するためのメソッドの概要もまとめられています。
Cache
インターフェースと HTTP キャッシュ
Cache
インターフェースを使用したことがない場合は、
次のように考えたくなるかもしれませんが、
少なくとも HTTP キャッシュに関係しますこれは明細書や請求書ではありません。
Cache
インターフェースは、HTTP キャッシュとは完全に別のキャッシュ メカニズムです。- すべて
Cache-Control
HTTP キャッシュに影響を与えるために使用する設定は、Cache
インターフェースに保存されるアセットには影響しません。
ブラウザ キャッシュは階層化されたものと考えるとわかりやすくなります。 HTTP キャッシュは、Key-Value ペアによって駆動される低レベルのキャッシュで、HTTP ヘッダーで表現されたディレクティブを指定します。
一方、Cache
インターフェースは、JavaScript API によって行われる高レベルのキャッシュです。
この方法は、比較的シンプルな HTTP Key-Value ペアを使用する場合よりも柔軟性に優れています。
キャッシュ戦略を可能にする仕組みの半分です。
Service Worker のキャッシュに関連する重要な API メソッドは次のとおりです。
CacheStorage.open
新しいCache
インスタンスを作成します。Cache.add
およびCache.put
ネットワーク レスポンスを Service Worker のキャッシュに保存します。Cache.match
Cache
インスタンス内のキャッシュに保存されたレスポンスを見つけます。Cache.delete
キャッシュに保存されたレスポンスをCache
インスタンスから削除する。
これらはほんの一部です。他にも役に立つ方法がありますが これらは、このガイドの後半で使用します。
シンプルな fetch
イベント
キャッシュ戦略のもう半分は、Service Worker の
fetch
イベント。
これまでこのドキュメントでは、「ネットワーク リクエストのインターセプト」について少し見てきましたが、
これは、Service Worker 内の fetch
イベントで発生します。
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('install', (event) => {
event.waitUntil(caches.open(cacheName));
});
self.addEventListener('fetch', async (event) => {
// Is this a request for an image?
if (event.request.destination === 'image') {
// Open the cache
event.respondWith(caches.open(cacheName).then((cache) => {
// Respond with the image from the cache or from the network
return cache.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request.url).then((fetchedResponse) => {
// Add the network response to the cache for future visits.
// Note: we need to make a copy of the response to save it in
// the cache and use the original as the request response.
cache.put(event.request, fetchedResponse.clone());
// Return the network response
return fetchedResponse;
});
});
}));
} else {
return;
}
});
これはおもちゃの例です。 皆様もご自身の目でお確かめください Service Worker で何ができるかが垣間見えます。 上記のコードは、次の処理を行います。
- リクエストの
destination
プロパティを調べて、これが画像リクエストかどうかを確認します。 - 画像が Service Worker のキャッシュにある場合は、そこから画像を提供します。 そうでない場合は、イメージをネットワークから取得します。 レスポンスをキャッシュに保存し、ネットワーク レスポンスを返します。
- 他のすべてのリクエストは、キャッシュとのやり取りなしで Service Worker を通過します。
フェッチの event
オブジェクトには、
request
プロパティ
各リクエストのタイプを識別するのに便利な情報があります。
url
これは、現在fetch
イベントによって処理されているネットワーク リクエストの URL です。method
これはリクエスト メソッド(例:GET
やPOST
など)。mode
リクエストのモードを記述します。'navigate'
の値は、HTML ドキュメントのリクエストを他のリクエストと区別するためによく使用されます。destination
リクエスト対象のコンテンツの種類を記述するため、リクエストされたアセットのファイル拡張子は使用しないようにします。
繰り返しになりますが、asynchrony はゲームの名前です。
install
イベントは
event.waitUntil
メソッドは Promise を受け取り、それが解決されるのを待ってからアクティベーションを続行します。
fetch
イベントでも、同様のイベント
event.respondWith
メソッド
非同期の関数の結果を出力するために使用できる
fetch
リクエスト
または Cache
インターフェースの
match
メソッド。
キャッシュ戦略
Cache
インスタンスと fetch
イベント ハンドラについてある程度理解できたところで、
Service Worker のキャッシュ戦略を詳しく見ていきます。
可能性はほぼ無限にありますが
このガイドは、Workbox に付属する戦略に沿って
これにより、Workbox の内部の仕組みを理解できます。
キャッシュのみ
「キャッシュのみ」という簡単なキャッシュ戦略から始めましょう。 ただ、Service Worker がページをコントロールしている場合、 キャッシュに移動されるだけです つまり、このパターンを機能させるには、キャッシュに保存されたアセットを事前にキャッシュに保存する必要があります。 Service Worker が更新されるまで、これらのアセットがキャッシュ内で更新されないようにする必要があります。
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
// Assets to precache
const precachedAssets = [
'/possum1.jpg',
'/possum2.jpg',
'/possum3.jpg',
'/possum4.jpg'
];
self.addEventListener('install', (event) => {
// Precache assets on install
event.waitUntil(caches.open(cacheName).then((cache) => {
return cache.addAll(precachedAssets);
}));
});
self.addEventListener('fetch', (event) => {
// Is this one of our precached assets?
const url = new URL(event.request.url);
const isPrecachedRequest = precachedAssets.includes(url.pathname);
if (isPrecachedRequest) {
// Grab the precached asset from the cache
event.respondWith(caches.open(cacheName).then((cache) => {
return cache.match(event.request.url);
}));
} else {
// Go to the network
return;
}
});
上図では、アセットの配列がインストール時に事前キャッシュされています。
Service Worker がフェッチを処理すると
fetch
イベントによって処理されるリクエスト URL が、事前キャッシュに保存されたアセットの配列にあるかどうかを確認します。
含まれている場合は、キャッシュからリソースを取得して、ネットワークをスキップします。
他のリクエストはネットワークを経由し
ネットワークのみに制限します。
この戦略を実際に確認するには
コンソールを開いてこちらのデモをご覧ください。
ネットワークのみ
「キャッシュのみ」の反対「ネットワークのみ」です ここでは、Service Worker のキャッシュとやり取りすることなく、Service Worker を介してリクエストがネットワークに渡されます。 これは、コンテンツの更新頻度(マークアップなど)を確保するための優れた戦略です。 その代償として、ユーザーがオフラインのときは動作しません。
リクエストがネットワークに渡されるようにするには、一致するリクエストで event.respondWith
を呼び出さないようにします。
明示的に指定したい場合は
ネットワークに渡すリクエストに対して、fetch
イベント コールバックで空の return;
をラップできます。
これは「キャッシュのみ」の事前キャッシュされていないリクエストに関する戦略デモ
最初にキャッシュし、ネットワークにフォールバック
この戦略では、もう少し複雑な作業が必要になります。 照合リクエストの場合、プロセスは次のようになります。
- リクエストはキャッシュにヒットします。アセットがキャッシュにある場合は、そこから配信します。
- リクエストがキャッシュにない場合は、ネットワークにアクセスします。
- ネットワーク リクエストが終了したら、それをキャッシュに追加し、 ネットワークからレスポンスを返します。
この戦略の例を以下に示します。この戦略を試すには、 ライブデモ:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
// Check if this is a request for an image
if (event.request.destination === 'image') {
event.respondWith(caches.open(cacheName).then((cache) => {
// Go to the cache first
return cache.match(event.request.url).then((cachedResponse) => {
// Return a cached response if we have one
if (cachedResponse) {
return cachedResponse;
}
// Otherwise, hit the network
return fetch(event.request).then((fetchedResponse) => {
// Add the network response to the cache for later visits
cache.put(event.request, fetchedResponse.clone());
// Return the network response
return fetchedResponse;
});
});
}));
} else {
return;
}
});
この例では画像のみを説明しますが これは、すべての静的アセット(CSS、JavaScript、画像、フォントなど)に適用できる優れた戦略です。 特にハッシュバージョン付きのものが 挙げられます HTTP キャッシュによって開始されるサーバーによるコンテンツの鮮度チェックを回避することで、不変アセットの処理を高速化できます。 さらに重要な点として、キャッシュに保存されたアセットはオフラインで使用できます。
ネットワーク ファースト、キャッシュにフォールバック
[最初にキャッシュ、次にネットワーク] をオンに切り替えた場合は頭に浮かんだ 「ネットワークファースト、キャッシュ 2 番目」にその一例を以下に紹介します
- まずリクエストのためにネットワークに接続し、そのレスポンスをキャッシュに保存します。
- 後でオフラインになった場合は、 キャッシュ内のそのレスポンスの最新バージョンにフォールバックします。
この戦略は、次のような場合に HTML または API リクエストに最適です。 最新バージョンのリソースが必要になった場合に ただし、最新バージョンにオフラインでアクセスできるようにするには、 HTML のリクエストに適用した場合は次のようになります。
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
// Check if this is a navigation request
if (event.request.mode === 'navigate') {
// Open the cache
event.respondWith(caches.open(cacheName).then((cache) => {
// Go to the network first
return fetch(event.request.url).then((fetchedResponse) => {
cache.put(event.request, fetchedResponse.clone());
return fetchedResponse;
}).catch(() => {
// If the network is unavailable, get
return cache.match(event.request.url);
});
}));
} else {
return;
}
});
これはデモでお試しいただけます。 まず、ページに移動します。HTML レスポンスがキャッシュに配置される前に、再読み込みが必要になる場合があります。 次にデベロッパーツールで オフライン接続をシミュレートする 再度読み込んでください。 最新の利用可能なバージョンがキャッシュからすぐに配信されます。
オフライン機能が重要な状況では ただし、マークアップや API データの最新版へのアクセスと、その機能とのバランスを取る必要があります。 「ネットワークを最初に、キャッシュを 2 番目にして」 その目標を達成するための強固な戦略となります。
Stale-while-revalidate
これまでに説明した戦略のうち、「Stale-while-revalidate」手法は最も複雑です。 2 つ目の戦略とある点で類似していますが、 リソースのアクセス速度を優先しますが、 バックグラウンドで最新の状態を保ちますこの戦略は次のようになります。
- アセットの最初のリクエストでネットワークから取得し、 キャッシュに保存してネットワーク レスポンスを返します。
- 後続のリクエストでは、まずキャッシュからアセットを提供し、次に「バックグラウンドで」配信します。 ネットワークに再度リクエストし、アセットのキャッシュ エントリを更新してください。
- その後のリクエストについては 前のステップでキャッシュに配置された、最後にネットワークから取得されたバージョンが返されます。
これは、常に最新の状態を維持することが重要な場合に最適な戦略です。 重要ではありません ソーシャル メディア サイトのアバターのようなものと考えてください。 ユーザーが近づくと更新されます ただし、すべてのリクエストに最新バージョンが厳密に必要なわけではありません。
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
if (event.request.destination === 'image') {
event.respondWith(caches.open(cacheName).then((cache) => {
return cache.match(event.request).then((cachedResponse) => {
const fetchedResponse = fetch(event.request).then((networkResponse) => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
return cachedResponse || fetchedResponse;
});
}));
} else {
return;
}
});
実際の動作は、
別のライブデモ
特にブラウザのデベロッパーツールの [ネットワーク]タブでは
およびその CacheStorage
ビューア(ブラウザのデベロッパー ツールにそのようなツールがある場合)
ワークボックスの方へ!
このドキュメントでは、Service Worker API の復習を 関連 API を提供します。 これで、Service Worker を直接使用して Workbox の微調整を行う方法について十分に学習しました。