ワーカーの概要

ウェブワーカーとサービス ワーカーがサイトのパフォーマンスを向上させる仕組みと、ウェブワーカーとサービス ワーカーの使い分け。

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

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

ワーカーがウェブサイトを改善する方法

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

iOS / Android アプリの開発では、アプリのメインスレッドがユーザー イベントに自由に応答できるようにするための一般的なパターンとして、オペレーションを別のスレッドにオフロードします。実際、最新バージョンの Android では、メインスレッドを長時間ブロックするとアプリがクラッシュします。

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

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

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

Window オブジェクトとウェブワーカー、サービス ワーカーの間の 2 つのリンクを示す図。

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

類似点

ウェブサイトで使用できるワーカーには、ウェブワーカーとサービス ワーカーの 2 種類があります。これらには、次のような共通点があります。

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

相違点

ウェブワーカーに委任できるほとんどの処理は、サービス ワーカーでも実行できると考えられますが、両者には重要な違いがあります。

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

ユースケース

2 種類のワーカーの違いから、どちらを使用すべきかがわかります。

ウェブワーカーのユースケースは、UI のブロックを回避するために、作業(重い計算など)をセカンダリ スレッドにオフロードすることに関連しています。

Window オブジェクトからウェブワーカーへのリンクを示す図。
  • 例: ビデオゲーム PROXX を構築したチームは、ユーザー入力とアニメーションを処理するために、メインスレッドをできるだけ空けておきたいと考えました。これを実現するために、ウェブワーカーを使用して、ゲームロジックと状態の維持を別のスレッドで実行しました。
ビデオゲーム PROXX のスクリーンショット。

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

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

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

ポッドキャスト PWA のスクリーンショット。
UI が更新され、ダウンロードの進行状況が表示されるようになりました(左)。サービス ワーカーのおかげで、すべてのタブが閉じられたときにもオペレーションの実行を継続できます(右)。

ツールとライブラリ

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

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

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

Workbox

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

次のステップ

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

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

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