配信中

プログレッシブ ウェブアプリの重要な側面は、信頼性です。迅速にアセットを読み込むことができるため、ネットワークが不安定であってもユーザーのエンゲージメントを維持し、すぐにフィードバックを提供できます。これは以下のようにして可能になります。Service Worker の fetch イベントにより、

取得イベント

対応ブラウザ

  • Chrome: 40。 <ph type="x-smartling-placeholder">
  • Edge: 17。 <ph type="x-smartling-placeholder">
  • Firefox: 44。 <ph type="x-smartling-placeholder">
  • Safari: 11.1。 <ph type="x-smartling-placeholder">

ソース

fetch イベントを使用すると、同一オリジンとクロスオリジンの両方のリクエストについて、Service Worker のスコープ内で PWA が送信したすべてのネットワーク リクエストをインターセプトできます。ナビゲーションとアセット リクエストに加え、インストール済みの Service Worker から取得することで、サイトの初回読み込み後のページ訪問をネットワーク呼び出しなしでレンダリングできます。

fetch ハンドラは、アプリからすべてのリクエスト(URL や HTTP ヘッダーを含む)を受け取り、アプリ デベロッパーがリクエストの処理方法を決定できるようにします。

Service Worker は、クライアントとネットワークの間に位置します。

Service Worker は、ネットワークにリクエストを転送したり、以前にキャッシュに保存されたレスポンスで応答したり、新しいレスポンスを作成したりできます。選択はあなた次第です。 たとえば、次のような例が考えられます。

self.addEventListener("fetch", event => {
    console.log(`URL requested: ${event.request.url}`);
});

リクエストへの応答

Service Worker にリクエストが届いたら、次の 2 つのことができます。無視してネットワークに送信することも、応答することもできます。Service Worker 内からリクエストに応答することで、ユーザーがオフラインの場合でも、何をどのように PWA に返すかを選択できます。

受信したリクエストに応答するには、次のように fetch イベント ハンドラ内から event.respondWith() を呼び出します。

// fetch event handler in your service worker file
self.addEventListener("fetch", event => {
    const response = .... // a response or a Promise of response
    event.respondWith(response);
});

respondWith() を同期的に呼び出し、Response オブジェクトを返す必要があります。ただし、非同期呼び出し内などでイベント ハンドラのフェッチ終了後に respondWith() を呼び出すことはできません。完全なレスポンスを待つ必要がある場合は、Response で解決される Promise を respondWith() に渡すことができます。

回答の作成

Fetch API を使用すると、JavaScript コードで HTTP レスポンスを作成し、Cache Storage API を使用してそのレスポンスをキャッシュに保存して、ウェブサーバーから返されるかのように返すことができます。

レスポンスを作成するには、新しい Response オブジェクトを作成し、本文とオプション(ステータスやヘッダーなど)を設定します。

const simpleResponse = new Response("Body of the HTTP response");

const options = {
   status: 200,
   headers: {
    'Content-type': 'text/html'
   }
};
const htmlResponse = new Response("<b>HTML</b> content", options)

キャッシュからのレスポンス

Service Worker からの HTTP レスポンスを提供する方法がわかったので、 次に、キャッシュ ストレージのインターフェースを使用してデバイスにアセットを保存します。

Cache Storage API を使用して、PWA から受信したリクエストがキャッシュで利用できるかどうかを確認し、利用可能な場合は、そのキャッシュで respondWith() に応答できます。 そのためには、まずキャッシュ内を検索する必要があります。最上位の caches インターフェースで使用できる match() 関数は、配信元内のすべての店舗または開いている 1 つのキャッシュ オブジェクトを検索します。

match() 関数は、HTTP リクエストまたは URL を引数として受け取り、対応するキーに関連付けられたレスポンスで解決される Promise を返します。

// Global search on all caches in the current origin
caches.match(urlOrRequest).then(response => {
   console.log(response ? response : "It's not in the cache");
});

// Cache-specific search
caches.open("pwa-assets").then(cache => {
  cache.match(urlOrRequest).then(response => {
    console.log(response ? response : "It's not in the cache");
  });
});

キャッシュ戦略

ブラウザのキャッシュからのみファイルを配信する方法は、すべてのユースケースに適しているわけではありません。たとえば、ユーザーまたはブラウザがキャッシュを削除できます。そのため、PWA のアセットを配信するための独自の戦略を策定する必要があります。 キャッシュ方法は 1 つに制限されません。URL パターンごとに異なるものを定義できます。たとえば、最小限の UI アセット、API 呼び出し、画像とデータ URL についてそれぞれ別の戦略を用意できます。 そのためには、ServiceWorkerGlobalScope.onfetchevent.request.url を読み、正規表現や URL パターンで解析します。(この資料の作成時点では、URL パターンはすべてのプラットフォームでサポートされているわけではありません)。

最も一般的な戦略は次のとおりです。

キャッシュ ファースト
まず、キャッシュに保存されたレスポンスを検索し、見つからない場合はネットワークにフォールバックします。
ネットワーク ファースト
最初にネットワークにレスポンスをリクエストし、レスポンスが返されない場合は、キャッシュでレスポンスを確認します。
再検証中に情報が古い
キャッシュからレスポンスを提供し、バックグラウンドで最新バージョンをリクエストし、次回アセットがリクエストされたときにキャッシュに保存します。
ネットワークのみ
常にネットワークからの応答やエラーで応答します。キャッシュが参照されることはありません。
キャッシュのみ
常にキャッシュからのレスポンス、またはエラーを返す。ネットワークがコンサルトされることはありません。この戦略を使用して配信されるアセットは、リクエストする前にキャッシュに追加する必要があります。

キャッシュ ファースト

この戦略を使用すると、Service Worker は一致するリクエストをキャッシュで探し、キャッシュされていれば対応するレスポンスを返します。それ以外の場合は、ネットワークからレスポンスを取得します(必要に応じて、今後の呼び出しのためにキャッシュを更新します)。キャッシュ レスポンスもネットワーク レスポンスもない場合、リクエストはエラーになります。ネットワークを経由せずにアセットを配信する方が速い傾向があるため、この戦略では鮮度よりもパフォーマンスが優先されます。

キャッシュ ファースト戦略

self.addEventListener("fetch", event => {
   event.respondWith(
     caches.match(event.request)
     .then(cachedResponse => {
       // It can update the cache to serve updated content on the next request
         return cachedResponse || fetch(event.request);
     }
   )
  )
});

ネットワーク ファースト

この戦略はキャッシュ ファースト戦略のミラーです。リクエストがネットワークから処理できるかどうかを確認し、処理できない場合はキャッシュからの取得を試みます。キャッシュ ファーストです。ネットワーク レスポンスもキャッシュ レスポンスもない場合、リクエストはエラーになります。通常、ネットワークからレスポンスを取得する方が、キャッシュからレスポンスを取得するよりも時間がかかります。この戦略では、パフォーマンスではなく更新されたコンテンツが優先されます。

ネットワーク ファースト戦略

self.addEventListener("fetch", event => {
   event.respondWith(
     fetch(event.request)
     .catch(error => {
       return caches.match(event.request) ;
     })
   );
});

再検証中に最新でない

「stale while revalidate」戦略では、キャッシュ内のレスポンスをすぐに返してから、ネットワークに更新がないかチェックします。見つかった場合は、キャッシュ内のレスポンスを置き換えます。この戦略では、常にネットワーク リクエストが実行されます。キャッシュされたリソースが見つかった場合でも、次回のリクエストで更新バージョンが使用されるように、キャッシュにあるリソースをネットワークから受信した情報で更新しようとするためです。したがって、この戦略ではキャッシュ ファースト戦略を迅速に提供し、バックグラウンドでキャッシュを更新できます。

戦略の再検証中に古くなった

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cachedResponse => {
        const networkFetch = fetch(event.request).then(response => {
          // update the cache with a clone of the network response
          const responseClone = response.clone()
          caches.open(url.searchParams.get('name')).then(cache => {
            cache.put(event.request, responseClone)
          })
          return response
        }).catch(function (reason) {
          console.error('ServiceWorker fetch failed: ', reason)
        })
        // prioritize cached response over network
        return cachedResponse || networkFetch
      }
    )
  )
})

ネットワークのみ

ネットワークのみの戦略は、Service Worker や Cache Storage API を使用しないブラウザの動作と似ています。リクエストは、ネットワークから取得できる場合にのみリソースを返します。多くの場合、オンラインのみの API リクエストなどのリソースで有用です。

ネットワークのみの戦略

キャッシュのみ

キャッシュのみの戦略では、リクエストがネットワークに送信されることはありません。すべての受信リクエストに対して、事前入力されたキャッシュ アイテムが使用されます。次のコードでは、fetch イベント ハンドラとキャッシュ ストレージの match メソッドを使用して、キャッシュのみに応答します。

self.addEventListener("fetch", event => {
   event.respondWith(caches.match(event.request));
});

キャッシュのみの戦略。

カスタム戦略

上記は一般的なキャッシュ戦略ですが、Service Worker とリクエストの処理方法は、お客様自身で決定する必要があります。いずれの方法でもニーズに合わない場合は、独自に作成してください。

たとえば、タイムアウトを設定したネットワーク ファースト戦略を使用して、更新されたコンテンツを優先させることができます。ただし、これは設定したしきい値内に応答がある場合に限ります。キャッシュに保存されたレスポンスとネットワーク レスポンスを結合して、Service Worker からの複雑なレスポンスを作成することもできます。

アセットの更新

PWA のキャッシュ アセットを最新の状態に保つことが難しい場合があります。戦略を再検証しながら最新状態を維持するという方法も一つの方法ですが、それだけではありません。アップデートのチャプターでは、アプリのコンテンツとアセットを最新の状態に保つさまざまな方法について説明します。

リソース