Service WorkerのOnInstallイベントでは、event.waitUntilの処理が終わるまでInstallを待ってくれる

こんにちは。 エキサイト株式会社の三浦です。

ブラウザに特別な方法でJavaScriptのコードを読み込ませると、そのコードを使ってバックグラウンドなどで様々な処理を行わせることが出来ます。

その機能は「Service Worker」と呼ばれるのですが、今回はそのService Workerのインストール時、 event.waitUntil という処理を使うことで、特定の処理が終わるまでインストールを待ってくれる、という話をしていきます。

Service Workerとは

Service Workerは、ブラウザにバックグラウンドで処理をさせるなど、応用的なことをさせることができる機能です。

developer.mozilla.org

サービスワーカーは、基本的にウェブアプリケーションブラウザー、そして(もし繋がっていれば)ネットワークの間に介在するプロキシサーバーのように振る舞います。これは、よりよいオフラインの操作性を可能にするように意図されており、ネットワークのリクエストに介在してネットワークの使用可否の状況に基づいて適切な対応を取ったり、サーバー上にある資産を更新したりします。また、プッシュ通知やバックグラウンド同期の API 群へのアクセスもできるようになります。

応用的なことができる分、通常WebページでJavaScriptを使うときとは異なり、単にページ上からscriptタグで呼び出すだけでなく、特別な登録が必要になったり、登録後にインストール・アクティベート処理が実行されたりします。

// 通常のJavascriptからService Worker用のJavascriptを登録する
navigator.serviceWorker.register('/service_worker.js')
// service_worker.js

// Service Workerがインストールされるときに呼ばれるイベント
self.addEventListener('install', event => {});

// Service Workerがアクティベートされるときに呼ばれるイベント
self.addEventListener('activate', event => {});

Service Workerのインストール時に処理を行いたい時どうするか

さて、Service Workerを使うということは、何かService Workerでしか出来ない処理がしたいということでしょう。

Service Workerだけで完結するような処理であればいいのですが、例えばバックエンド側に何か登録する必要があるなど、Service Workerの登録に合わせて別の処理をさせたい場合があります。

そういった時、上記の install イベントを使うと便利です。

例えば、以下のようにAPIにリクエストを投げたいとします。

// APIを通じてuserを登録する
register() {
    return fetch(`https://sample.site.com/user/register`, {
        method: 'POST'
    });
}

この時、以下のように実行することが出来ます。

// service_worker.js

// Service Workerがインストールされるときに呼ばれるイベント
self.addEventListener('install', event => {
    this.register();
});

これで、Service Workerがインストールされる時、同時にユーザの登録ができるようになりました。

ただし実は、これだけだと問題があります。

例えば、何らかの事情でAPIに障害が起き、アクセスできない状態のときにService Workerのインストールが起きたらどうすれば良いでしょうか?

基本的にService Workerのインストールは、Service Workerに使用するJavaScriptに変更が無いと起きないものなので、1回失敗しただけで、JavaScriptを更新しない限りその後は登録ができなくなってしまいます。

実はService Workerではそのような自体に備え、 event.waitUntil という機能を使うことが出来ます。

Service Workerのインストール時、 event.waitUntil を使う

event.WaitUntil は、以下のように使うことが出来ます。

// service_worker.js

// Service Workerがインストールされるときに呼ばれるイベント
self.addEventListener('install', event => {
    event.waitUntil(this.register());
});

これによってどうなるかと言うと、 this.register();APIエラーなどが起き、返り値の Promisereject 状態の場合、「インストールが失敗した」と判断されるようになります。

そして「インストールが失敗した」と判断された場合、またインストールを試行してくれるため、「Service Workerのインストールが完了した = 登録が完了した」を保証することができるようになるのです。

最後に

Service Workerは便利ですが、処理が各ユーザのブラウザで行われるものなので、処理としてはエンジニアの手元からかなり離れてしまい、それが開発の難しさの原因となっていると考えています。

その中でこのinstallイベント内の event.waitUntil は、動作を保証してくれる非常に有用な機能なので、ぜひ使っていきましょう。