knowledge base

マークアップ/フロントエンドエンジニアのWEB制作における備忘録です。平日はWEB屋、休日は社会人劇団の主宰・劇作家をしています。

【PWA】シリーズPWA (3) Service Workerについて

これまでさんざんServiceWorkerという言葉が出てきましたが、ServiceWorkerとはブラウザとインターネットの間に立って色々と便利なことをしてくれるものです。

プロキシのようなイメージだと分かりやすいかもしれません。これがPWAそのものであるといっても過言ではありません。

前回予告なくJSのコードを書いてしまったので、ここからは技術的に掘り下げてゆきたいと思います。

Service Workerってなんなのよ (Service Workerのえほん)

ぜひこちらを読んでください。細かいことはわからなくて良いです。

知って欲しいのは、「ブラウザとネットワークの間に立っている存在」ということです。

qiita.com

 

前回か前々回の記事で、PWAにすることはとても簡単、けれどServiceWorkerに色々便利なことをやってもらうにはJSのスキルやノウハウが必要と書きました。

色々便利なこととは、例えばキャッシュを制御することによる高速化、WebPushを受け取ってブラウザに通知を表示する、などです。

それらはすべてブラウザとネットワークの間に立っているからこそできる所業の数々です。

これから先は、どうやったらキャッシュを制御したり、通知を表示したりできるか、その実装方法についてまとめます。

Service Workerを生成して実際に動かす前に

いきなり技術的な話に入っていきます。

まずはJSを書く前に、ServiceWorkerについて知ってゆきます。

動かすためには基本的に2種類のJSが必要

  • main.js (ファイル名は何でもいいが便宜上こう呼びます):ブラウザからServiceWorkerを制御するためのJS。navigator.serviceWorker にてServiceWorkerを制御するための「ServiceWorkerContainer」インターフェイスを参照し、これを通じてServiceWorkerとやりとりします。ServiceWorkerContainerインターフェイスは ServiceWorkerの登録、削除、更新及び送受信を行います。
  • serviceworker.js (ファイル名は何でもいいが便宜上こう呼びます):Service Workerにキャッシュや通知などをさせているJS。ServiceWorkerにはselfで参照する。selfのイベントリスナに関数を紐づけて、好きな処理を書いていく。使えるイベントについては後述。

特徴など

  • Service Workerは必要なときに起動するので、 イベントハンドリング中に なにか値を変数に保持しておいたとしても、次のイベントハンドリングの際には消えてしまいます。そのため、イベントの間で持続する情報を保持したい場合にはIndexedDBを使う必要があります。複数のページ間でのデータのやり取りが手軽にできるものではないと思っておいたほうがよいでしょう。
  • ServiceWorkerは自身が生成される階層(serviceworker.jsのある階層)より上の階層は制御できない。反対に、自身が生成された階層以下であれば、制御対象のディレクトリを指定できる
  • httpslocalhost 上でしか動作しない。

ServiceWorkerのライフサイクル

  • parsed :parsedは初期状態です。Service Workerはまだインストールされておらず、まだService Workerとして呼び出されたスクリプトが読み込まれたくらいの段階です。すぐさま次の状態へ遷移するため、あまり意識することはありません。
  • installing:installingは名前のとおり、Service Workerをインストールしている最中の状態です。Service Workerの新規インストールか、あるいは更新されている場合にもこの状態をとります。この際にService Workerのライフサイクルイベントであるinstallイベントが発生しており、Service Worker側のJavaScriptではこのイベントをハンドリングして必要に応じた(たとえばキャッシュを構築するような)インストール処理を行うこともできます。すでに有効なService Workerがインストール済みで、更新もされていない場合にはactivatedまでスキップされます。 
  • installed :installedは先のinstalling状態を問題なく通過した状態です。この段階でService Workerのインストールには成功していますが、まだService Workerは有効になっていません。Service Workerを新規インストールしている場合には、すぐに次のactivating状態へと遷移します。Service Workerを更新してる場合には、古いService WorkerがまだWebページを制御しているので、新しいService Workerはこの状態に留まります。この状態に留まった新しいService Workerが有効になるには、ユーザーがWebページから離れるなどして、ブラウザが安全に古いService Workerを解放できた後に再度Webページを開くことで、次のactivating状態に移る必要があります。また、この状態はオンライン上のドキュメントではwaitingと呼ばれることも多いです。
  • activating :installedの次の状態がactivatingです。Service Workerの新規インストール時には前段階のinstalledからすぐにこの状態になります。更新の場合には、古いService Workerに代わって新しいService Workerが有効になる段階です。installingのときと同じように、activating時にはライフサイクルイベントのactivateイベントが発生します。Service Worker側のJavaScriptではイベントをハンドリングして必要に応じた処理(たとえば古いキャッシュを破棄するような)をすることもできます。 activated :Service Workerが、対象のWebページを問題なく制御下に置いた状態です。この状態でService WorkerはWebページからのリクエストに反応するfetchや、Webページからのメッセージを受け取るmessageイベントを待つことができます。
  • redundant :次の理由でService Workerが無効となった状態です。(1)installイベント中にエラーが発生した(2)activateイベント中にエラーが発生した(3)新しいService Workerと置き換えられた

以下参考

app.codegrid.net

qiita.com

 

ServiceWorkerのイベント

各ライフサイクルにうつったときや、リクエストを横取りした時などにイベントが発火します。

  • installイベント :ServiceWorkerが登録された時(インストール成功とは違う)。registerメソッドで登録された時。
  • activateイベント : ServiceWorker がpush や sync や fetch などのイベントを処理できるようになった時。
  • messageイベント : クライアントから送られたpostMessageを受け取った時(ちなみにクライアントにpostMessageを送ることも可能)。
  • fetchイベント :ブラウザからのリクエストを横取りした時。
  • syncイベント :オフラインからオンラインになり、状態を同期した時。
  • pushイベント :サーバーからのプッシュ通知を受け取った時。