Cache API: クイックガイド

Cache API を使用して、アプリケーション データをオフラインで使用可能にする方法について説明します。

Cache API は、ネットワーク リクエストとそれに対応するレスポンスを保存および取得するためのシステムです。これらは、アプリケーションの実行中に作成される通常のリクエストとレスポンスの場合もあれば、後で使用するためにデータを保存する目的でのみ作成される場合もあります。

Cache API は、Service Worker がネットワーク リクエストをキャッシュに保存し、ネットワークの速度や可用性に関係なく迅速なレスポンスを提供できるようにするために作成されました。ただし、API は一般的なストレージ メカニズムとして使用することもできます。

どこで利用できますか?

Cache API はすべての最新ブラウザで使用できます。これはグローバル caches プロパティで公開されているため、シンプルな機能検出で API の有無をテストできます。

const cacheAvailable = 'caches' in self;

対応ブラウザ

  • 40
  • 16
  • 41
  • 11.1

ソース

Cache API には、ウィンドウ、iframe、ワーカー、Service Worker からアクセスできます。

保存できるデータ

キャッシュには、それぞれ HTTP リクエストとレスポンスを表す Request オブジェクトと Response オブジェクトのペアのみが格納されます。ただし、リクエストとレスポンスには、HTTP 経由で転送可能なあらゆる種類のデータを含めることができます。

保存できるデータ量はどれくらいですか?

要するに、大量、少なくとも数百メガバイト、場合によっては数百ギガバイト以上です。ブラウザの実装はさまざまですが、使用可能なストレージ容量は通常、デバイスで使用可能なストレージ容量に基づきます。

キャッシュの作成とオープン

キャッシュを開くには、caches.open(name) メソッドを使用して、キャッシュの名前を 1 つのパラメータとして渡します。名前付きキャッシュが存在しない場合は作成されます。このメソッドは、Cache オブジェクトで解決される Promise を返します。

const cache = await caches.open('my-cache');
// do something with cache...

キャッシュへの追加

キャッシュにアイテムを追加するには、addaddAllput の 3 つの方法があります。3 つのメソッドはすべて Promise を返します。

cache.add

最初は cache.add() です。Request または URL(string)のいずれかのパラメータを取ります。ネットワークにリクエストを行い、レスポンスをキャッシュに保存します。取得が失敗した場合、またはレスポンスのステータス コードが 200 の範囲外の場合は、何も保存されず、Promise は拒否します。CORS モードではないクロスオリジン リクエストは、0status を返すため、保存できません。このようなリクエストは put でのみ保存できます。

// Retreive data.json from the server and store the response.
cache.add(new Request('/data.json'));

// Retreive data.json from the server and store the response.
cache.add('/data.json');

cache.addAll

次は cache.addAll() です。add() と似ていますが、Request オブジェクトまたは URL(string)の配列を受け取ります。これはリクエストごとに cache.add を呼び出す場合と同様に機能しますが、1 つのリクエストがキャッシュに保存されない場合に Promise が拒否する点が異なります。

const urls = ['/weather/today.json', '/weather/tomorrow.json'];
cache.addAll(urls);

いずれの場合も、一致する既存のエントリは新しいエントリによって上書きされます。この場合、retrievingのセクションで説明したものと同じマッチング ルールが使用されます。

cache.put

最後は cache.put() です。これを使用すると、ネットワークからのレスポンスを保存したり、独自の Response を作成して保存したりできます。これは 2 つのパラメータを取ります。1 つ目は Request オブジェクトか URL(string)のいずれかです。2 つ目は、ネットワークから生成されたか、コードで生成された Response です。

// Retrieve data.json from the server and store the response.
cache.put('/data.json');

// Create a new entry for test.json and store the newly created response.
cache.put('/test.json', new Response('{"foo": "bar"}'));

// Retrieve data.json from the 3rd party site and store the response.
cache.put('https://example.com/data.json');

put() メソッドは add()addAll() よりも制限が緩く、非 CORS レスポンスや、レスポンスのステータス コードが 200 以外のレスポンスを格納できます。これにより、同じリクエストに対する以前のレスポンスが上書きされます。

Request オブジェクトの作成

格納する情報の URL を使用して、Request オブジェクトを作成します。

const request = new Request('/my-data-store/item-id');

Response オブジェクトの操作

Response オブジェクト コンストラクタは、BlobArrayBufferFormData オブジェクト、文字列など、さまざまな種類のデータを受け入れます。

const imageBlob = new Blob([data], {type: 'image/jpeg'});
const imageResponse = new Response(imageBlob);
const stringResponse = new Response('Hello world');

Response の MIME タイプを設定するには、適切なヘッダーを設定します。

  const options = {
    headers: {
      'Content-Type': 'application/json'
    }
  }
  const jsonResponse = new Response('{}', options);

Response を取得してその本文にアクセスする場合、使用できるヘルパー メソッドがいくつかあります。それぞれ、異なる型の値で解決される Promise を返します。

メソッド 説明
arrayBuffer バイトにシリアル化された本文を含む ArrayBuffer を返します。
blob Blob を返します。ResponseBlob で作成された場合、この新しい Blob は同じ型になります。それ以外の場合は、ResponseContent-Type が使用されます。
text 本文のバイトを UTF-8 でエンコードされた文字列として解釈します。
json 本文のバイトを UTF-8 でエンコードされた文字列として解釈し、JSON として解析を試みます。結果のオブジェクトを返します。文字列を JSON として解析できない場合は TypeError をスローします。
formData 本文のバイトを multipart/form-data または application/x-www-form-urlencoded としてエンコードされた HTML フォームとして解釈します。FormData オブジェクトを返すか、データを解析できない場合は TypeError をスローします。
body ボディデータの ReadableStream を返します。

次に例を示します。

const response = new Response('Hello world');
const buffer = await response.arrayBuffer();
console.log(new Uint8Array(buffer));
// Uint8Array(11) [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]

キャッシュからの取得

キャッシュ内のアイテムを検索するには、match メソッドを使用します。

const response = await cache.match(request);
console.log(request, response);

request が文字列の場合、ブラウザは new Request(request) を呼び出して Request に変換します。この関数は、一致するエントリが見つかった場合は Response に解決される Promise を返し、見つからない場合は undefined を返します。

2 つの Requests が一致するかどうかを判断するために、ブラウザは URL 以外の情報も使用します。クエリ文字列、Vary ヘッダー、HTTP メソッド(GETPOSTPUT など)が異なる 2 つのリクエストは、異なるものとみなされます。

これらの一部またはすべてを無視するには、オプション オブジェクトを 2 番目のパラメータとして渡します。

const options = {
  ignoreSearch: true,
  ignoreMethod: true,
  ignoreVary: true
};

const response = await cache.match(request, options);
// do something with the response

キャッシュに保存されたリクエストが複数一致する場合は、最初に作成されたリクエストが返されます。一致するすべてのレスポンスを取得するには、cache.matchAll() を使用します。

const options = {
  ignoreSearch: true,
  ignoreMethod: true,
  ignoreVary: true
};

const responses = await cache.matchAll(request, options);
console.log(`There are ${responses.length} matching responses.`);

ショートカットとして、キャッシュごとに cache.match() を呼び出す代わりに、caches.match() を使用してすべてのキャッシュを一度に検索できます。

検索機能

Cache API は、Response オブジェクトと照合するエントリを除き、リクエストやレスポンスを検索する手段を提供しません。ただし、フィルタリングまたはインデックスを作成して、独自の検索を実装できます。

フィルタリング

独自の検索を実装する 1 つの方法は、すべてのエントリを反復処理して、目的のエントリに絞り込むことです。URL が .png で終わるすべてのアイテムを検索するとします。

async function findImages() {
  // Get a list of all of the caches for this origin
  const cacheNames = await caches.keys();
  const result = [];

  for (const name of cacheNames) {
    // Open the cache
    const cache = await caches.open(name);

    // Get a list of entries. Each item is a Request object
    for (const request of await cache.keys()) {
      // If the request URL matches, add the response to the result
      if (request.url.endsWith('.png')) {
        result.push(await cache.match(request));
      }
    }
  }

  return result;
}

このようにして、Request オブジェクトと Response オブジェクトの任意のプロパティを使用してエントリをフィルタリングできます。大規模なデータセットを検索する場合は、処理に時間がかかります。

インデックスの作成

独自の検索を実装するもう 1 つの方法は、検索可能なエントリのインデックスを別に保持し、そのインデックスを IndexedDB に保存することです。これは IndexedDB が設計した種類のオペレーションであるため、エントリ数が多くなるとパフォーマンスが大幅に向上します。

Request の URL を検索可能なプロパティとともに保存すると、検索後に正しいキャッシュ エントリを簡単に取得できます。

アイテムの削除

キャッシュからアイテムを削除するには:

cache.delete(request);

request には Request または URL 文字列を指定できます。また、このメソッドは cache.match と同じオプション オブジェクトを受け取ります。これにより、同じ URL について複数の Request/Response ペアを削除できます。

cache.delete('/example/file.txt', {ignoreVary: true, ignoreSearch: true});

キャッシュの削除

キャッシュを削除するには、caches.delete(name) を呼び出します。この関数は、キャッシュが存在し、削除された場合は true に解決される Promise を返し、そうでない場合は false を返します。

Thanks

WebFundamentals に最初に掲載されたこの記事の原稿を執筆してくれた Mat Scales に感謝します。