Service Worker

ユーザーは、ネットワーク接続が遅い、不安定な場合、あるいはオフラインの場合でも、アプリが起動することを期待します。 メディア トラック、チケット、旅行プランなど、最後に操作したコンテンツが利用可能かつ使用可能であることを期待します。 リクエストを実行できない場合、ユーザーは通知なく失敗したりクラッシュしたりするのではなく、アプリが通知することを期待します。そして、ユーザーはそれらすべてを手早く行いたいと考えています。この調査からわかるように、ミリ秒の差は数百万ドルですが、読み込み時間を 0.1 秒改善しただけでも、コンバージョン率は最大で 10% 向上します。まとめると、ユーザーは PWA に信頼性を期待しているため、Service Worker を用意しています。

Hello Service Worker

PWA とサーバーの間でデバイス側で実行されるミドルウェア プロキシとしての Service Worker。独自のサーバーとクロスドメイン サーバーの両方が含まれます。

アプリが Service Worker のスコープに含まれるリソースをリクエストすると(ユーザーがオフラインの場合など)、Service Worker はネットワーク プロキシとして機能してリクエストをインターセプトします。その後、Cache Storage API を介してキャッシュからリソースを提供するか、Service Worker を使用しない場合と同様にネットワークからリソースを提供するか、ローカルのアルゴリズムからリソースを作成するかを決定できます。これにより、プラットフォーム アプリと同様のエクスペリエンスを提供できます。完全にオフラインで動作することもできます。

Service Worker の登録

Service Worker でページを制御するには、そのページを PWA に登録する必要があります。つまり、ユーザーが初めて PWA にアクセスしたとき、Service Worker はまだページを制御していないため、ネットワーク リクエストはサーバーに直接送信されます。

ブラウザが Service Worker API をサポートしていることを確認したら、PWA で Service Worker を登録できます。読み込まれると、Service Worker は PWA とネットワークの間にショップを設定し、リクエストをインターセプトして対応するレスポンスを提供します。

if ('serviceWorker' in navigator) {
   navigator.serviceWorker.register("/serviceworker.js");
}

Service Worker が登録されているかどうかを確認する

Service Worker が登録されているかどうかを確認するには、任意のブラウザでデベロッパー ツールを使用します。

Firefox と Chromium ベースのブラウザ(Microsoft Edge、Google Chrome、Samsung Internet)の場合:

  1. デベロッパー ツールを開き、[アプリケーション] タブをクリックします。
  2. 左側のペインで [Service Worker] を選択します。
  3. Service Worker のスクリプト URL のステータスが「Activated」であることを確認します。(このステータスの意味については、この章のライフサイクルのセクションをご覧ください)。Firefox では、ステータスは「実行中」または「停止」になります。

Safari の場合:

  1. [開発] メニューをクリックし、[Service Worker] サブメニューをクリックします。
  2. 現在のオリジンのエントリがサブメニューに表示されていることを確認します。Service Worker のコンテキストで Inspector が開きます。
Chrome、Firefox、Safari 上の Service Worker デベロッパー ツール。
Chrome、Firefox、Safari 上の Service Worker デベロッパー ツール

範囲

Service Worker が存在するフォルダによってスコープが決まります。example.com/my-pwa/sw.js にある Service Worker は、my-pwa パス以下のすべてのナビゲーション(example.com/my-pwa/demos/ など)を制御できます。Service Worker は、スコープ内のアイテム(ページ、ワーカー、総称して「クライアント」)のみを制御できます。対象はブラウザタブと PWA ウィンドウです。

スコープごとに 1 つの Service Worker のみを使用できます。アクティブかつ実行中の場合、メモリ内のクライアントの数(PWA ウィンドウやブラウザタブなど)の数にかかわらず、通常は 1 つのインスタンスしか使用できません。

Safari にはパーティションと呼ばれるより複雑なスコープ管理があり、クロスドメイン iframe がある場合、スコープの動作に影響します。WebKit の実装について詳しくは、WebKit のブログ投稿をご覧ください。

ライフサイクル

Service Worker には、インストール方法を規定するライフサイクルがあります。これは PWA のインストールとは別のものです。Service Worker のライフサイクルは、Service Worker の登録から始まります。その後、ブラウザは Service Worker ファイルをダウンロードし、解析します。解析が成功すると、install イベントが発生します。install イベントは 1 回だけ発生します。

Service Worker のインストールは、ユーザーが PWA をインストールしなくても、ユーザーに許可を求めることなく自動的に行われます。Service Worker API は、デスクトップ デバイスの Safari や Firefox など、PWA のインストールをサポートしていないプラットフォームでも利用可能です。

インストール後、Service Worker は PWA を含むクライアントをまだ制御できません。まず有効にする必要があります。Service Worker でクライアントを制御する準備が整うと、activate イベントが発生します。ただし、Service Worker を登録したページが管理されるわけではありません。デフォルトでは、ページを再読み込みするか PWA を再度開くかのいずれかにより、次にそのページに移動するまで、Service Worker は制御を行いません。

Service Worker のグローバル スコープ内のイベントをリッスンするには、self オブジェクトを使用します。

serviceworker.js

// This code executes in its own worker or thread
self.addEventListener("install", event => {
   console.log("Service worker installed");
});
self.addEventListener("activate", event => {
   console.log("Service worker activated");
});

Service Worker の更新

Service Worker は、現在クライアントを制御している Service Worker と、同じファイルの(サーバーからの)新しいバージョンがバイト単位で異なっていることをブラウザが検出すると更新されます。

インストールが正常に完了した後、新しい Service Worker は、既存の(古い)Service Worker がクライアントを制御しなくなるまで、アクティブ化を待機します。この状態は「待機中」と呼ばれます。ブラウザでは、この状態に基づいて、一度に 1 つのバージョンの Service Worker のみが実行されます。ページを更新したり、PWA を再度開いたりしても、新しい Service Worker は制御されません。ユーザーは、現在の Service Worker を使用してすべてのタブとウィンドウを閉じるか、それらのウィンドウから移動してから、戻る必要があります。そうして初めて、新しい Service Worker が制御を引き継ぎます。詳しくは、Service Worker のライフサイクルに関する記事をご覧ください。

Service Worker の存続期間

インストールと登録が完了すると、Service Worker はスコープ内のすべてのネットワーク リクエストを管理できるようになります。独自のスレッドで実行され、有効化と終了はブラウザによって制御されます。これにより、PWA を開く前でも、開いた後でも機能します。Service Worker は独自のスレッドで実行されますが、Service Worker の実行間でメモリ内状態が維持される保証はありません。そのため、実行時に再利用したいものが IndexedDB または他の永続ストレージで利用可能であることを確認してください。

Service Worker がまだ実行されていない場合は、範囲内のネットワーク リクエストが要求されたとき、または定期的なバックグラウンド同期やプッシュ メッセージなどのトリガーとなるイベントを受信するたびに開始されます。

Service Worker は無期限に存続できるわけではありません。正確なタイミングはブラウザによって異なりますが、Service Worker は数秒間アイドル状態であったり、ビジー状態の時間が長すぎたりした場合に終了します。Service Worker が終了し、起動のイベントが発生すると、Service Worker が再起動します。

機能

登録済みのアクティブな Service Worker により、PWA のメインとは実行ライフサイクルがまったく異なるスレッドが作成されます。ただし、デフォルトでは Service Worker ファイル自体に動作はありません。リソースのキャッシュ保存や提供はコード側で行う必要があるため、キャッシュ保存や提供は行われません。その方法については、以降の章で説明します。

Service Worker の機能は、プロキシや HTTP リクエストの処理だけにとどまりません。バックグラウンド コードの実行、ウェブプッシュ通知、決済処理など、他の目的で他の機能も利用できます。これらの追加については、機能に関する章で説明します。

リソース