Service Worker というメインのブラウザスレッドの外側で実行される特殊な JavaScript を使うことで、メインスレッドを空き状態にすることができるため、ブラウザのパフォーマンスが向上する。
ブラウザのスレッドはシングルスレッド(setTimeoutやrequestAnimationFrameも処理の割り込みをしているだけで元来シングルスレッドである)であるため、通常のスクリプトはUIや他のスクリプトによって処理をブロックすることがあるが、Service Worker を使用するとメインスレッドの状態にかかわらずに独立したスレッドで動作するため、バックグラウンドに処理を進めることができる。

ブラウザとネットワークの間に立って、ブラウザで発生するネットワークリクエストの処理(通常のリクエスト、キャッシュの使用、新しいレスポンスの作成などの判断をどのようにするか決定する)をしたり、事前データの読み込み(プリロード)や、プッシュ通知、バックグラウンド同期(オフラインになってもネットワークの接続状態が戻るまでデータ通信を保留し後から処理が可能)などが可能となるが、DOMの操作など通常の JavaScript でできることができなかったりなどいくつかの制限がある。

Service Worker はグローバルオブジェクトとしてWorkerGlobalScope を持ち、Worker内部でこれを利用することができる。

SPA はだいたい PWA を採用しているため、Service Worker を使用していることになる。
Service Worker を使うと、ハイブリッドレンダリングが可能になる。

ハイブリッドレンダリングとは、初期表示の部分をサーバー側でレンダリングし、ブラウザでナビゲーションを行った際にはService Worker がナビゲーションイベントを処理し、ページ遷移時に通常のようにHTMLを取得するのではなく、クライアントサイドでHTMLを取得しレンダリングすることでページ遷移をしているように見せかける技術のことで、クローラーの対策を行いつつ、ユーザーサイドにはより早いコンテンツ表示を提供する技術のことである。

こういったAPIのテストに Mock Service Worker を使用すると通信をインターセプトして GraphQL と REST API どちらの API も使うことができるため、JSONファイルやJSオブジェクトを作成する必要がなくなり開発しやすくなる(ローディングやエラー処理も再現できる)し、テストや Storybook のモックにもすぐに流用できるのでお勧め。

使用例

// Main Threadからのメッセージをリッスン
self.addEventListener('message', e => {
  let result;
  // 処理を実行
  // Main Threadに処理を戻す
  self.postMessage(result);
}, false);
// Workerを作成 "./worker.js"
const worker = new Worker("worker.js");

// Workerからのメッセージをリッスン
worker.addEventListener('message', e => {
  console.log(e.data);
}, false);

// Workerにメッセージを送信
worker.postMessage('');