ネットワーク タイムアウトの強制

ネットワーク接続はあるのに、接続速度が遅すぎる、または接続がオンラインと認識されることがあります。Service Worker が混在している状況では、ネットワークファーストのキャッシュ戦略ではネットワークからのレスポンスの取得に時間がかかりすぎたり、リクエストがハングしたり、読み込みスピナーが無限に回転し、エラーページが表示されたりすることがあります。

いずれにせよ、アセットやページについて、キャッシュから一定時間経過した後に最後にキャッシュされたレスポンスにフォールバックすることが望ましい場合がありますが、これは Workbox が対応できる別の問題です。

networkTimeoutSeconds の使用

NetworkFirst 戦略または NetworkOnly 戦略を使用する場合、ネットワーク リクエストにタイムアウトを強制的に適用できます。これらの戦略には networkTimeoutSeconds オプションが用意されています。このオプションは、ネットワーク レスポンスが到着して最後のキャッシュ バージョンを返すまでに Service Worker が待機する秒数を指定します。

// sw.js
import { NetworkFirst } from 'workbox-strategies';
import { registerRoute, NavigationRoute } from 'workbox-routing';

// Only wait for three seconds before returning the last
// cached version of the requested page.
const navigationRoute = new NavigationRoute(new NetworkFirst({
  networkTimeoutSeconds: 3,
  cacheName: 'navigations'
}));

registerRoute(navigationRoute);

上記のコードは、ネットワーク ファーストのナビゲーション リクエストに対してはタイムアウトし、3 秒後に最後にキャッシュされたバージョンを使用するよう Service Worker に指示しています。ナビゲーション リクエストで使用すると、以前にアクセスしたページの最後のキャッシュ レスポンスへのアクセスが保証されます。

しかし、アクセスしようとしているページのキャッシュに古いレスポンスがない場合はどうなるでしょうか。このような場合は、一般的なオフライン HTML ページへのフォールバック レスポンスを確立できます。

import {registerRoute, NavigationRoute} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';

// Hardcode the fallback cache name and the offline
// HTML fallback's URL for failed responses
const FALLBACK_CACHE_NAME = 'offline-fallback';
const FALLBACK_HTML = '/offline.html';

// Cache the fallback HTML during installation.
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(FALLBACK_CACHE_NAME).then((cache) => cache.add(FALLBACK_HTML)),
  );
});

// Apply a network-only strategy to navigation requests.
// If offline, or if more than five seconds pass before there's a
// network response, fall back to the cached offline HTML.
const networkWithFallbackStrategy = new NetworkOnly({
  networkTimeoutSeconds: 5,
  plugins: [
    {
      handlerDidError: async () => {
        return await caches.match(FALLBACK_HTML, {
          cacheName: FALLBACK_CACHE_NAME,
        });
      },
    },
  ],
});

// Register the route to handle all navigations.
registerRoute(new NavigationRoute(networkWithFallbackStrategy));

これは、NetworkFirst 戦略で networkTimeoutSeconds を使用すると、タイムアウトが発生し、URL のキャッシュが一致しない場合にハンドラがエラー レスポンスを返すためです。その場合は、handlerDidError Workbox プラグインがフォールバックとして汎用レスポンスを提供できます。

待ち時間はどれくらいですか?

リクエスト(特にナビゲーション リクエスト)のタイムアウトを強制する場合、ユーザーの待ち時間が長くなりすぎないようにすることと、タイムアウトが早すぎることとの間で適切なバランスを取る必要があります。待機時間が長すぎると、接続速度が遅いユーザーがタイムアウトになる前にバウンスしてしまうリスクがあります。タイムアウトが短すぎると、キャッシュから古いコンテンツが不必要に提供される可能性があります。

正解は「場合によって異なる」です。ブログなどのサイトを運営していて、コンテンツをあまり更新していない場合、キャッシュの内容はおそらく「新鮮」であるため、あまり待つ必要はありません。十分ですただし、よりインタラクティブなウェブサイトやウェブアプリの場合は、もう少し待ってから、Service Worker のキャッシュから古いデータを過度に配信しないようにすることをおすすめします。

現場で指標を記録している場合は、Time to First Byte(TTFB)スコアと First Contentful Paint(FCP)スコアの 75 パーセンタイルを確認して、ナビゲーション リクエストの待ち時間が長くなる可能性がある場所を把握します。線を引く箇所が見えてくるかもしれません。