Smart Communication Design Company
ホーム > ナレッジ > Blog > フロントエンドBlog > 2019年7月 > Request.destinationでリソースの種類別にキャッシュ戦略

Request.destinationでリソースの種類別にキャッシュ戦略


UI開発者 古川

Request.destinationRequestインターフェイスのプロパティで、リクエストしているコンテンツの種類を文字列で返します。これをService Workerのfetchイベント時に用いると、リソースの種類別にキャッシュ戦略を切り替えることができます。

Request.destinationの使い方

Request.destinationでは一体どんな文字列が返されるのでしょうか。Fetch StandardのRequest.destinationの仕様の一部を抜粋します。

A request has an associated destination, which is the empty string, "audio", "audioworklet", "document", "embed", "font", "image", "manifest", "object", "paintworklet", "report", "script", "serviceworker", "sharedworker", "style", "track", "video", "worker", or "xslt". Unless stated otherwise it is the empty string.

たとえば画像であればimage、フォントであればfontなどが取得できるようです。XMLHttpRequestfetch()で取得されたリソースなど、Request.destinationでリソースの種別が判別できなかったものに関しては空の文字列で返却されます。

それらをふまえ、Service WorkerのfetchイベントでRequset.destinationを用いた例が以下のソースコードです。

self.addEventListener('fetch', (event) => {
  const destination = event.request.destination;

  switch (destination) {
    case 'document':
      event.respondWith(
        cacheFirst(event).catch(() => {
          return caches.match('./offline.html');
        })
      );
      break;

    case 'image':
      event.respondWith(
        cacheFirst(event).catch(() => {
          return caches.match('./offline.png');
        })
      );
      break;

    case 'style':
    case 'script':
      event.respondWith(
        cacheFirst(event)
      );
      break;

    default: 
      event.respondWith(
        networkOnly(event)
      );
      break;
  }
});

上記の例では以下のような処理を行っています:

上のリストの内容を簡単にまとめると、HTMLのキャッシュがなければオフラインページが表示されます。HTMLのキャッシュがある場合でも画像のキャッシュがなんらかの理由で残っていない場合は、画像のみオフライン用に用意した画像で表示できます。

またRequest.destinationと、リクエストをURLで判別する方法を組み合わせることで、さらに細かくキャッシュ戦略を分けて提供することが可能です。

以下のソースコードは、Request.destinationが「images」でかつURLが「.webp」で終わるリクエストを判別する例です。

self.addEventListener('fetch', (event) => {
  const destination = event.request.destination;
  const requestURL = new URL(event.request.url);

  switch (destination) {
    // ...
    case 'images': {
      if(requestURL.endWidth('.webp')) {
        event.respondWith(/* do something */);
      } else {
        event.respondWith(/* do something */);
      }

      break;
    }
    // ...
  }
});

まとめ

Cache APIでキャッシュ可能な容量は限られるので、容量が大きいリソース、たとえば画像やフォントなどはキャッシュせずフォールバックを提供したいなどリソースごとに切り分けをしたいケースにRequest.distinationは有用です。

オフライン時などにどうWebページが見えるとユーザーフレンドリーなのか、シナリオを十分考慮しながら効率的にキャッシュ戦略を考えていきたいです。