kitak blog

Kみたいなエンジニアになりたいブログ

ServiceWorker で、ネットワークから取得しようして失敗したらキャッシュにフォールバックするやつ

ここ最近、ServiceWorker を使って色々試しているのだけど、その中のひとつ。

以下の内容を、エントリーの HTML や参照系の API に適用して、アプリケーションのオフライン対応を実現する。通常はネットワークから取得した最新の内容を使うが、オフラインやネットワークが不安定な場合はキャッシュの内容を使う。

  • ネットワークから取得しようとして失敗したらキャッシュを使う
  • ネットワークから取得するとき、1秒のタイムアウトを設定する
  • ネットワークから取得しようとして成功したらキャッシュに保存する
  • ネットワークから取得しようとして失敗した場合、キャッシュが存在しなかった場合はログにその旨を出力する

ServiceWorker 内で使える API は Promise を返すものがほとんどなので、Promise を駆使するかんじ。

var CACHE_NAME = 'v1';

var fetchWithTimeout = function(request) {
    return new Promise(function(resolve, reject) {
        setTimeout(reject, 1000);
        return fetch(request).then(resolve);
    });
};

self.addEventListener('fetch', function(event) {
    // 本当はここでパスやヘッダーの内容を見て、キャッシュすべき対象か調べる
    event.respondWith(
        fetchWithTimeout(event.request)
            .then(function(response) {
                return caches.open(CACHE_NAME).then(function(cache) {
                    console.log('Put to cache', response);
                    cache.put(event.request, response.clone());
                    return response;
                });
            })
            .catch(function(e) {
                console.error('Failed to fetch', e);
                return caches.open(CACHE_NAME).then(function(cache) {
                    console.log('Fallback to cache', event.request);
                    var response = cache.match(event.request);
                    if (!response) {
                      console.error('Missing cache', event.request);
                      return;
                    }
                    return response; 
                });
            })
    );
});