ワーカーの概要

ウェブ ワーカーと Service Worker を使用してサイトのパフォーマンスを向上させる方法と、Web Worker と Service Worker の使い分けについて説明します。

Andrew Guan
Andrew Guan

この概要では、ウェブ ワーカーと Service Worker がウェブサイトのパフォーマンスを向上させる方法と、Web Worker と Service Worker の使い分けについて説明します。ウィンドウと Service Worker の通信の特定のパターンについては、このシリーズの残りの部分をご覧ください。

ブラウザは単一のスレッド(メインスレッド)を使用して、ウェブページ内のすべての JavaScript を実行するだけでなく、ページのレンダリングやガベージ コレクションの実行などのタスクも実行します。JavaScript コードを過度に実行するとメインスレッドがブロックされ、ブラウザによるこれらのタスクの実行が遅れ、ユーザー エクスペリエンスが低下する可能性があります。

iOS/Android アプリの開発では、アプリのメインスレッドがユーザー イベントに自由にアクセスできるようにする一般的なパターンは、追加のスレッドに操作をオフロードすることです。実際、最新バージョンの Android では、メインスレッドのブロックが長すぎるとアプリのクラッシュにつながります

ウェブ上では、JavaScript はシングル スレッドのコンセプトに基づいて設計されており、共有メモリなどのアプリのようなマルチスレッド モデルを実装するために必要な機能がありません。

こうした制限はあるものの、ウェブでも同様のパターンを実現するには、ワーカーを使用してバックグラウンド スレッドでスクリプトを実行します。これにより、ワーカーはメインスレッドに干渉することなく、タスクを実行できます。ワーカーは JavaScript スコープ全体であり、共有メモリを伴わずに別のスレッドで実行されます。

この投稿では、2 種類のワーカー(ウェブ ワーカーと Service Worker)と、それらの類似点と相違点、本番ウェブサイトでこれらのワーカーを使用する一般的なパターンについて説明します。

Window オブジェクトと、Web Worker および Service Worker の間の 2 つのリンクを示す図。

ウェブワーカーとサービス ワーカー

類似点

ウェブワーカーサービス ワーカーは、ウェブサイトで利用できる 2 種類のワーカーです。この 2 つの共通点は次のとおりです。

  • どちらもセカンダリ スレッドで実行されるため、メインスレッドとユーザー インターフェースをブロックせずに JavaScript コードを実行できます。
  • ユーザーは Window オブジェクトと Document オブジェクトにアクセスできないため、DOM を直接操作できず、ブラウザ API へのアクセスが制限されています。

相違点

ウェブ ワーカーに委任できるほとんどのことは、Service Worker でも実行できると考える方もいるかもしれませんが、両者には重要な違いがあります。

  • ウェブワーカーとは異なり、Service Worker ではネットワーク リクエストを(fetch イベントで)インターセプトし、(push イベントを介して)バックグラウンドで Push API イベントをリッスンできます。
  • 1 つのページから複数のウェブワーカーを生成できますが、1 つの Service Worker が、その登録に使用されたスコープのアクティブなタブをすべて制御します。
  • ウェブワーカーの存続期間は、それが属するタブと密接に結びついていますが、Service Worker のライフサイクルは独立しています。このため、ウェブ ワーカーが動作しているタブを閉じるとウェブ ワーカーは終了しますが、サイトでアクティブなタブが開いていなくても、Service Worker はバックグラウンドでの実行を継続できます。

使用例

両方のタイプのワーカーの違いから、どちらのワーカーを使用するかが決まっています。

ウェブワーカーのユースケースは、UI をブロックしないように、一般的には作業(負荷の高い計算など)をセカンダリ スレッドにオフロードすることに関連しています。

Window オブジェクトからウェブワーカーへのリンクを示す図。
  • 例: ビデオゲーム PROXX を作成しているチームが、ユーザー入力とアニメーションを処理するために、メインスレッドをできる限り無料にしたいと考えていました。そのために、ウェブワーカーを使用して、別のスレッドでゲームロジックと状態のメンテナンスを実行しました。
ビデオゲーム「PROXX」のスクリーンショット。

Service Worker のタスクは一般に、ネットワーク プロキシとしての動作、バックグラウンド タスクの処理、キャッシュ保存やオフライン処理などに関連しています。

ビデオゲーム「PROXX」のスクリーンショット。

例: ポッドキャスト PWA で、ユーザーがエピソード全編をダウンロードしてオフラインで聴けるようにできます。そのためには、Service Worker、特に Background Fetch API を使用できます。そうすることで、エピソードのダウンロード中にユーザーがタブを閉じても、タスクが中断されることはありません。

ポッドキャスト PWA のスクリーンショット。
UI が更新され、ダウンロードの進行状況が表示されます(左)。Service Worker により、すべてのタブを閉じたときにオペレーションを続行できます(右)。

ツールとライブラリ

ウィンドウとワーカーの通信は、異なる下位レベルの API を使用して実装できます。幸いなことに、このプロセスを抽象化して最も一般的なユースケースに対応するライブラリがあります。このセクションでは、ウェブワーカーと Service Worker のウィンドウを処理する ComlinkWorkbox の 2 つについて説明します。

ビデオゲーム「PROXX」のスクリーンショット。

Comlink は、ウェブ ワーカーを使用するウェブサイトを構築する際に、基盤となる多くの詳細情報を処理する小さな(1.6k)RPC ライブラリです。PROXXSquoosh などのウェブサイトで使用されています。その動機とコードサンプルの概要については、こちらをご覧ください。

Workbox

Workbox は、Service Worker を使用するウェブサイトを構築するための一般的なライブラリです。キャッシュ保存、オフライン、バックグラウンド同期などに関する一連のベスト プラクティスがパッケージ化されています。workbox-window モジュールは、Service Worker とページの間でメッセージを交換するための便利な方法を提供します。

次のステップ

このシリーズの残りの部分では、ウィンドウと Service Worker の通信パターンに焦点を当てます。

  • 命令型キャッシュ ガイド: ページから Service Worker を呼び出して、リソースを事前にキャッシュに保存します(プリフェッチのシナリオなど)。
  • 更新情報のブロードキャスト: Service Worker からページを呼び出して、重要な更新(ウェブサイトの新しいバージョンが利用可能になったなど)を通知します。
  • 双方向通信: タスクを Service Worker に委任し(大量のダウンロードなど)、進行状況をページに知らせます。

ウィンドウとウェブ ワーカーの通信パターンについては、ウェブ ワーカーを使用してブラウザのメインスレッドから JavaScript を実行するをご覧ください。