Cache

Cache インターフェイスは、Request / Response オブジェクトのペアのためのストレージの仕組みを提供します。例えば、 ServiceWorker のライフサイクルの一部としてこれらをキャッシュします。なお、 Cache インターフェイスは、ワーカーだけでなくウィンドウスコープにも公開されています。サービスワーカーの仕様書で定義されているものですが、必ずしもサービスワーカーとの組み合わせで使用する必要はありません。

単一のオリジンが、複数の名前付き Cache オブジェクトを持つことができます。 (例えば ServiceWorker の中などで) スクリプトがどのように Cache を更新するかを実装する必要があります。 Cache 内のアイテムは、明示的に要求しない限り更新されませんし、削除しない限り有効期限はありません。 CacheStorage.open() を使用して特定の名前付き Cache オブジェクトを開き、それから任意の Cache のメソッドを呼び出して Cache を管理します。

また、定期的にキャッシュエントリを一掃する必要があります。各ブラウザーは、指定されたオリジンが使用できるキャッシュストレージの総量に厳しい制限を設けています。キャッシュ容量の概算の使用量は StorageEstimate API を用いて確認することができます。ブラウザーはディスク容量の管理に最善を尽くしますが、あるオリジンのキャッシュストレージを削除することがあります。ブラウザーはふつう、あるオリジンのデータをすべて削除するか、まったく削除しないかのいずれかです。名前を用いてキャッシュをバージョン管理し、安全に操作できるスクリプトのバージョンからのみキャッシュを使用するようにしてください。詳細は、古いキャッシュの削除を確認してください。

メモ: キーの照合アルゴリズムは、値の中にある VARY ヘッダーに依存しています。そのため、新しいキーを照合するには、キャッシュ内のエントリのキーと値の両方を調べる必要があります。

メモ: キャッシュ API は HTTP のキャッシュヘッダーを尊重しません。

メソッド

Cache.match(request, options)
Cache オブジェクトで最初に一致したリクエストに関連するレスポンスで解決する Promise を返します。
Cache.matchAll(request, options)
Cache オブジェクトで一致するすべてのリクエストの配列で解決する Promise を返します。
Cache.add(request)
URL を受け取り、それを取得して、指定されたキャッシュに結果のレスポンスオブジェクトを追加します。機能的には fetch() を呼び出してから、 put() を使用してキャッシュに結果を追加するのと同等です。
Cache.addAll(requests)
URL の配列を受け取り、それらを取得して指定されたキャッシュに結果のレスポンスオブジェクトを追加します。
Cache.put(request, response)
リクエストとそのレスポンスの両方を受け取り、指定されたキャッシュへ追加します。
Cache.delete(request, options)
キーがリクエストである Cache エントリを探し、見つかった場合は Cache エントリを削除して、 true で解決する Promise を返します。 Cache エントリが見つからない場合、Promise は false で解決します。
Cache.keys(request, options)
Cache キーの配列で解決する Promise を返します。

このコードスニペットは、service worker selective caching sample からのものです (selective caching をライブで見る)。このコードでは CacheStorage.open() を使用して、 font/ で始まる Content-Type ヘッダー用の Cache オブジェクトを開きます。

そしてこのコードは、 Cache.match() を使用してすでにキャッシュ内に一致するフォントがあるかどうかを確認し、もしあれば、それを返します。一致するフォントがなかった場合は、コードはネットワークからフォントを取得して、 Cache.put() を用いて取得したリソースをキャッシュします。

このコードは fetch() の操作で発生する例外を処理します。なお、 HTTP のエラーレスポンス (404 など) はこの例外を発生させません。適切なエラーコードを持つ通常のレスポンスオブジェクトを返します。

このコードスニペットでは、サービスワーカーで使用されるバージョン付きキャッシュのベストプラクティスも示しています。この例ではキャッシュが1つしかありませんが、キャッシュが複数でも同じアプローチが利用できます。これはキャッシュの一括指定識別子を、具体的なバージョン付けされたキャッシュ名に対応させます。このコードはまた、 CURRENT_CACHES で名前が指定されていないキャッシュをすべて削除します。

このコード例において、 cachesServiceWorkerGlobalScope のプロパティです。これは CacheStorage オブジェクトを保持し、 CacheStorage インターフェイスでアクセスすることができます。これは WindowOrWorkerGlobalScope ミックスインを実装したものです。

メモ: Chrome では、 chrome://inspect/#service-workers にアクセスして、登録されたサービスワーカーの下の "inspect" リンクをクリックすると、 service-worker.js スクリプトが行う様々なアクションのログ状態を見ることができます。
var CACHE_VERSION = 1;
var CURRENT_CACHES = {
  font: 'font-cache-v' + CACHE_VERSION
};

self.addEventListener('activate', function(event) {
  // CURRENT_CACHES で指定されていないすべてのキャッシュを削除します。
  // この例ではキャッシュは1つしかありませんが、同じロジックが
  // 複数のバージョン化されたキャッシュがある場合を処理します。
  var expectedCacheNamesSet = new Set(Object.values(CURRENT_CACHES));
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (!expectedCacheNamesSet.has(cacheName)) {
            // このキャッシュ名が「予期される」キャッシュ名のセットに存在しない場合は、削除します。
            console.log('Deleting out of date cache:', cacheName);
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

self.addEventListener('fetch', function(event) {
  console.log('Handling fetch event for', event.request.url);

  event.respondWith(
    caches.open(CURRENT_CACHES.font).then(function(cache) {
      return cache.match(event.request).then(function(response) {
        if (response) {
          // event.request のエントリがキャッシュにある場合、レスポンスが定義され、それを返すことができます。
          // この例では、フォントリソースのみがキャッシュされることに注意してください。
          console.log(' Found response in cache:', response);

          return response;
        }

        // それ以外の場合、event.request のエントリがキャッシュにない場合、
        // レスポンスは undefined となり、リソースを fetch() する必要があります。
        console.log(' No response for %s found in cache. About to fetch ' +
          'from network...', event.request.url);

        // 後で cache.put() の呼び出しで使用する可能性があるため、リクエストで .clone() を呼び出します。
        // fetch() とcache.put() の両方がリクエストを「消費」するため、コピーを作成する必要があります。
        // (https://fetch.spec.whatwg.org/#dom-request-clone を参照)
        return fetch(event.request.clone()).then(function(response) {
          console.log('  Response for %s from network is: %O',
            event.request.url, response);

          if (response.status < 400 &&
              response.headers.has('content-type') &&
              response.headers.get('content-type').match(/^font\//i)) {
            // これにより、エラーであることがわかっているレスポンス(つまり、HTTP ステータスコード 4xx または 5xx)のキャッシュが回避されます。
            // また、フォントに対応するレスポンスのみをキャッシュする必要があります。
            // つまり、"font/" で始まる Content-Type レスポンスヘッダーを持ちます。
            // 不透明なフィルタされたレスポンス(https://fetch.spec.whatwg.org/#concept-filtered-response-opaque)の場合、
            // レスポンスヘッダーにアクセスできないので、このチェックは常に失敗し、フォントはキャッシュされないことに注意してください。
            // すべての Google Web Fonts は CORS をサポートするドメインから提供されるため、ここでは問題になりません。
            // ただし、CORS をサポートしていないクロスオリジンドメインから他のリソースをキャッシュしようとしている場合は、注意が必要です。
            // レスポンスで .clone() を呼び出して、そのコピーをキャッシュに保存します。
            // そうすることで、制御されたページに戻る元のレスポンスオブジェクトを保持できます。
            // (https://fetch.spec.whatwg.org/#dom-response-clone を参照)
            console.log('  Caching the response to', event.request.url);
            cache.put(event.request, response.clone());
          } else {
            console.log('  Not caching the response to', event.request.url);
          }

          // 元のレスポンスオブジェクトを返します。これは、リソース要求を満たすために使用されます。
          return response;
        });
      }).catch(function(error) {
        // この catch() は、match() または fetch() 操作から発生する例外を処理します。
        // HTTP エラーレスポンス(404 など)は例外をトリガーしないことに注意してください。
        // 適切なエラーコードが設定された通常のレスポンスオブジェクトを返します。
        console.error('  Error in fetch handler:', error);

        throw error;
      });
    })
  );
});

クッキーのキャッシュへの格納

Fetch API では Set-Cookie ヘッダーを、 Response オブジェクトを fetch() から返す前に削除する必要があります。したがって、キャッシュに含まれる Response はヘッダーを含みません。

仕様書

仕様書 状態 備考
Service Workers
Cache の定義
草案 初回定義

ブラウザーの互換性

BCD tables only load in the browser

関連情報