Service Worker 登録のタイミングのベスト プラクティス
Service Worker は、ウェブアプリへの再アクセスを高速化できますが、Service Worker の初回インストールによってユーザーの最初のアクセス エクスペリエンスが低下しないように措置を講じる必要があります。
通常、最初のページが読み込まれるまで Service Worker の登録を延期すると、ユーザー(特に、ネットワーク接続が遅いモバイル端末のユーザー)は最適なエクスペリエンスが得られます。
一般的な登録ボイラープレート
Service Worker の詳細を読んだことがある場合は、次のようなボイラープレートを見たことがあるでしょう。
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js');
}
これに console.log()
文や、前回の Service Worker 登録のアップデートを検出するコードが含まれる場合があり、これらはページを更新するようユーザーに知らせる手段として使用されます。ただし、標準のいくつかのコード行が少し異なるだけです。
では、「navigator.serviceWorker.register
」には何か違いがあるのでしょうか?従うべきベスト プラクティスはありますか?驚くことではありませんが(この記事がここですぐに終わるわけはありませんから)、答えは両方とも「はい」です。
ユーザーの初回アクセス
ユーザーがウェブアプリにはじめてアクセスする場合を考察してみましょう。Service Worker はまだなく、最終的にインストールされる Service Worker があるかどうかをブラウザが事前に知ることはできません。
デベロッパーの優先順位は、ブラウザがインタラクティブなページの表示に最小限必要なクリティカル リソースを迅速に取得できるようにすることです。レスポンスの取得を遅らせるものは、迅速なインタラクティブ エクスペリエンスの敵です。
ここで、JavaScript またはページでレンダリングする必要がある画像をダウンロードするプロセスで、ブラウザがバックグラウンド スレッドまたはプロセス(簡略化のためにスレッドを想定します)の開始を決定するとします。あなたは強力なパソコンではなく、世界の大部分で主要端末と見なされている能力の低いスマートフォンを使用しています。この追加のスレッドをスピンアップすると、ブラウザがインタラクティブなウェブページのレンダリングに費やす可能性がある CPU 時間とメモリの競合が発生します。
アイドル状態のバックグラウンド スレッドが大きな変化をもたらす可能性はあまりありません。ただし、スレッドがアイドル状態ではなく、ネットワークからリソースのダウンロードを開始する場合はどうでしょう。CPU やメモリの競合に関する懸念よりも、多くのモバイル端末が利用できる帯域幅の制限に関する懸念を優先すべきです。帯域幅は貴重であるため、同時にセカンダリ リソースをダウンロードすることでクリティカル リソースを浪費しないでください。
つまり、新しい Service Worker スレッドをスピンアップして、リソースのダウンロードとキャッシュをバックグラウンドで行うことは、ユーザーが初めてサイトにアクセスしたときに、最短でインタラクティブ エクスペリエンスを提供するという目標に対して効果的であるということです。
ボイラープレートの改善
解決策として、navigator.serviceWorker.register()
を呼び出すタイミングを選択することで Service Worker の起動を制御します。単純な経験則では、次のように window
で load
event
がトリガーされるまで登録を遅らせます。
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/service-worker.js');
});
}
ただし、Service Worker の登録を開始する適切なタイミングは、ウェブアプリが読み込まれた直後の動作によっても異なります。たとえば、Google I/O 2016 ウェブアプリは、メイン画面に遷移する前に短いアニメーションを表示します。Google のチームは、アニメーションの表示中に Service Worker 登録を開始すると、ローエンドのモバイル端末でアニメーションの品質が低下する場合があることを発見しました。ブラウザが数秒間アイドル状態になる可能性が高い場合、ユーザーに不快感を与えないよう、アニメーションが終わるまで Service Worker 登録を遅らせました。
同様に、ページの読み込み後に追加設定を行うフレームワークをウェブアプリで使用している場合は、その作業の完了を知らせるフレームワーク固有のイベントを探します。
2 回目以降の訪問
これまでは初回訪問時に重点を置いてきましたが、Service Worker の登録が遅れると、サイトへの再訪問にどのような影響があるでしょうか。驚かれるかもしれませんが、影響はまったくありません。
Service Worker は登録されると、install
と activate
のライフサイクル イベントを通過します。有効にすると、Service Worker はその後のウェブアプリへのアクセスの fetch
イベントを処理できるようになります。Service Worker は、スコープ内のページに対するリクエストが行われる前に起動します。これは、次のように考えると合理的です。既存の Service Worker がページへのアクセスの前に実行されていない場合は、ナビゲーション リクエストの fetch
イベントを処理できません。
したがって、アクティブな Service Worker が存在する場合は、navigator.serviceWorker.register()
を呼び出すタイミングや、実際に呼び出すかどうかに関係なく、Service Worker スクリプトの URL を変更しない限り、navigator.serviceWorker.register()
は 2 回目以降のアクセス中は実質的に何もしません。呼び出されるタイミングは関係ありません
早く登録する理由
できるだけ早く Service Worker を登録することが理にかなっているシナリオはありますか?たとえば、Service Worker が clients.claim()
を使用して初回アクセス時のページを制御し、その fetch
ハンドラの内部でランタイム キャッシュを積極的に実行する場合です。この場合は、Service Worker をできるだけ早くアクティブにして、後で取得する可能性があるリソースをランタイム キャッシュに移入するとメリットがあります。ウェブアプリがこのカテゴリに属する場合は、一歩離れて、Service Worker の install
ハンドラがメインページのリクエストと帯域幅を取り合うリソースを要求していないことを確認することをお勧めします。
テスト
最初のアクセスをシミュレートするのに適した方法は、ウェブアプリを Chrome のシークレット ウィンドウで開き、Chrome の DevTools でネットワーク トラフィックを確認することです。ウェブ デベロッパーは、ウェブアプリのローカル インスタンスを 1 日に何十回も再読み込みします。ただし、既に Service Worker が存在し、キャッシュが十分に入力されている場合にサイトに再アクセスすると、新しいユーザーと同じエクスペリエンスが得られず、発生するおそれのある問題を簡単に無視してしまいます。
登録のタイミングによって生じる可能性がある違いの例を以下に示します。両方のスクリーンショットは、低速の接続をシミュレートするためにネットワーク スロットリングを使用して、シークレット モードでサンプルアプリにアクセスしている間に撮影されたものです。
上のスクリーンショットは、できるだけ早く Service Worker 登録を実行するようにサンプルが変更されたときのネットワーク トラフィックを示しています。プリキャッシュ リクエスト(Service Worker の install
ハンドラから発信された、横に歯車アイコンがあるエントリ)は、ページの表示に必要な他のリソースへのリクエストと混在しています。
上のスクリーンショットでは、ページの読み込みが終わるまで Service Worker 登録が遅延されています。帯域幅の競合を回避して、すべてのリソースがネットワークから取得されるまでプリキャッシュ リクエストが始まらないことがわかります。さらに、事前キャッシュするアイテムの一部は、すでにブラウザの HTTP キャッシュ(サイズ列に (from disk cache)
があるアイテム)にあるため、ネットワークに再度アクセスすることなく、Service Worker のキャッシュにデータを入力できます。
この種のテストを実際のモバイル ネットワーク上の実際のローエンド デバイスから実行すれば、さらにポイントとなります。Chrome のリモート デバッグ機能を利用すると、Android スマートフォンを USB 経由でデスクトップ マシンに接続し、多くのユーザーが実際に体験している状況を反映したテストを実行できます。
まとめ
まとめると、最優先すべきは、ユーザーの初回訪問エクスペリエンスを最適にすることです。最初のアクセス時にページが読み込まれるまで Service Worker の登録を遅らせると、この確実化を確実に実現できます。再アクセス時にも、Service Worker のすべてのメリットを享受できます。
Service Worker の初期登録を最初のページの読み込み後まで遅らせる簡単な方法は、次のコードを使用することです。
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/service-worker.js');
});
}