序章

サービスワーカーは、オフラインキャッシュ、プッシュ通知、バックグラウンド同期などを担当するため、プログレッシブWebアプリ(PWA)で非常に重要な役割を果たします。 この記事では、サービスワーカーのライフサイクルと、ライフサイクルの各段階で何ができるかをわかりやすく説明します。

サービスワーカーを有効に活用するためには、サービスライフサイクルを理解することが不可欠です。 サービスワーカーのライフサイクルは、主に次の3つのフェーズで構成されます。

  • 登録
  • インストール
  • アクティベーション

それぞれを見ていきましょう。

登録

ServiceWorkerは基本的にJavaScriptファイルです。 Service Workerファイルを通常のJavaScriptファイルと区別する1つの点は、ServiceWorkerがブラウザーのメインUIスレッドから離れたバックグラウンドで実行されることです。 Service Workerの使用を開始する前に、バックグラウンドプロセスとして登録する必要があります。 これはライフサイクルの最初のフェーズです。 サービスワーカーはまだすべてのブラウザーでサポートされているわけではないため、最初にブラウザーがサービスワーカーをサポートしていることを確認する必要があります。 以下は、サービスワーカーを登録するために使用できるコードです。

app.js
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.js')
    .then(function (registration) {
        console.log('Service worker registered!');
    })
    .catch(function (err) {
        console.log('Registration failed!');
    })
}

まず、ブラウザがService Workerをサポートしているかどうか、つまりnavigatorオブジェクトにserviceWorkerプロパティがあるかどうかを確認します。 サポートされている場合にのみ、サービスワーカーを登録します。 register()メソッドは、Service Workerスクリプトへのパスを取得し、promiseを返します。

サービスワーカーを登録する時点で、サービスワーカーのスコープを定義することもできます。 サービスワーカーのスコープによって、サービスワーカーが制御できるページが決まります。 デフォルトでは、スコープはServiceWorkerスクリプトの場所によって定義されます。

app.js
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.js', {
        scope: '/blog/'
    })
    .then(function (registration) {
        console.log('Service worker registered!');
    })
    .catch(function (err) {
        console.log('Registration failed!');
    })
}

register()メソッドは、Service Workerスクリプトへのパスを受け入れるだけでなく、オプションのオブジェクトを受け入れることもできます。このオブジェクトでは、ServiceWorkerのscopeを定義できます。 ここでは、ServiceWorkerのスコープを/blog/に定義します。これにより、ServiceWorkerはblogディレクトリのみに制限されます。

インストール

Service Workerが正常に登録されたからといって、インストールされたわけではありません。 そこで、ライフサイクルのインストールフェーズが始まります。 Service Workerが正常に登録されると、スクリプトがダウンロードされ、ブラウザはServiceWorkerのインストールを試みます。 Service Workerは、次のいずれかの場合にのみインストールされます。

  • サービスワーカーは以前に登録されていません
  • Service Workerスクリプトが変更されます(1バイトであっても)。

Service Workerがインストールされると、installイベントが発生します。 このイベントをリッスンして、application0固有のタスクを実行できます。 たとえば、この時点でアプリケーションの静的アセットをキャッシュできます。

sw.js
const assetsToCache = [
    '/index.html',
    '/about.html',
    '/css/app.css',
    '/js/app.js',
]

self.addEventListener('install', function (event) {
    event.waitUntil(
        caches.open('staticAssetsCache').then(function (cache) {
              return cache.addAll(assetsToCache);
        })
      );
});

ここでは、キャッシュAPIのopen()メソッドを使用しています。このメソッドは、キャッシュの名前(この場合はstaticAssetsCache)を受け入れて、開く(既に存在する場合)か、作成して返します。約束。 約束が解決されると、つまりthen()内で、キャッシュするURLの配列を受け入れるCacheAPIのaddAll()を再び利用します。 open()メソッドはpromiseを返すため、event.waitUntil()内にラップする必要があります。これにより、promiseが解決されるまでServiceWorkerのインストールが遅延します。 約束が拒否された場合、installイベントは失敗し、サービスワーカーは破棄されます。

アクティベーション

インストールが成功すると、ServiceWorkerはinstalled状態になり(まだアクティブではありません)、その間、現在のServiceWorkerからページの制御を取得するのを待ちます。 次に、ライフサイクルの次のフェーズであるアクティブ化フェーズに進みます。 サービスワーカーは、インストール時にすぐにはアクティブ化されません。 サービスワーカーは、次のいずれかの場合にのみアクティブになります(つまり、アクティブになります)。

  • 現在アクティブなサービスワーカーがいない場合
  • ServiceWorkerスクリプトのinstallイベントハンドラーでself.skipWaiting()が呼び出された場合
  • ユーザーがページを更新した場合

skipWaiting()メソッドを使用してServiceWorkerをアクティブ化する例は、次のようになります。

sw.js
self.addEventListener('install', function (event) {
    self.skipWaiting();

    event.waitUntil(
           // static assets caching
      );
});

activateイベントは、サービスワーカーがアクティブになると発生します。 installイベントと同様に、activateイベントをリッスンして、アプリケーション固有のタスクを実行することもできます。 たとえば、キャッシュをクリアするには、次のようにします。

sw.js
const cacheVersion = 'v1';

self.addEventListener('activate', function (event) { 
    event.waitUntil( 
        caches.keys().then(function (cacheNames) {
            cacheNames.map(function (cacheName) {
                if (cacheName.indexOf(cacheVersion) < 0) { 
                    return caches.delete(cacheName);
                   } 
                }); 
            });
        }) 
    ); 
});

上記のスニペットは、指定されたすべてのキャッシュをループし、キャッシュが現在のServiceWorkerに属していない場合は既存のキャッシュを削除します。

Service Workerがアクティブ化されると、ページを完全に制御できるようになります。 Service Workerがアクティブになると、fetchpushsyncなどのイベントを処理できるようになります。

sw.js

self.addEventListener('fetch', function (event) {
    event.respondWith(caches.match(event.request))
    .then(function (response) {
        return response || fetch(event.request);
    });
});

サービスワーカーがアクティブになった後、上記の機能イベントを受信しなかった場合、サービスワーカーはidle状態になります。 しばらくアイドル状態になった後、ServiceWorkerはterminated状態になります。 これは、ServiceWorkerがアンインストールまたは登録解除されたことを意味するものではありません。 実際、サービスワーカーは、機能イベントの受信を開始するとすぐに再びアイドル状態になります。

以下は、サービスワーカーのライフサイクルの視覚的な要約です。

The Service Worker Lifecycle

結論

この記事では、サービスワーカーのライフサイクル、つまりライフサイクルの最終段階で発生するイベントについて説明しました。 また、これらのイベントのいくつかにフックすることで、サービスワーカーと一緒にできることをいくつか調べました。