WEB開発をしている人なら「Service Worker」という言葉を聞いたことがある人もいるかと思います。
Service Workerは多くの有名なサービスで活用されており、ユーザー体験の向上に貢献している技術です。
ここではService Workerとは何かを簡単に解説しています。
Service Workerとは何か?
Service Workerはブラウザがバックグラウンドで実行するJavaScriptファイルで、その最も重要な役割は、Webサイトを「オフラインでも使えるようにすること」と「超高速にすること」です。
もう少し具体的に言うと、Webページとは独立して動作し、ネットワークリクエストの制御やキャッシュ管理、プッシュ通知といった役割を担います。
Service Workerの主な役割
Service Workerの主な役割は次の3つです。
- オフラインでも使える
- 表示の高速化
- 通知を送る
オフラインでも使える
Service Workerはウェブサイトにアクセスしたときに、必要なデータ(画像、文字情報など)をスマホなどのアクセスしたデバイスの中に「一時保存(キャッシュ)」します。
例えるなら、「後で読むために自分用に本をコピーしておく」ようなものです。
Service Workerがコピーしたデータがデバイスの中にあるので、インターネットに繋がらない場所に行ったとしても、Webサイトを表示することができます。
ただし、勝手にずっと動いているわけではなく、必要なときにだけ起動して「仕事をする→終わったら休む」というイメージです。
表示の高速化
Service Workerがキャッシュしたデータをすぐに表示してくれるため、次に同じサイトを訪れたときに、サーバーまでデータを取りに行く必要がなくなります。
これにより、ページの読み込み時間が大幅に短縮され、サイトを非常にサクサクと快適に利用できます。
通知を送る
Service Workerは、サイトを閉じていても、新しい情報が来たときにプッシュ通知を送ることができます。これは、アプリからの通知と同じ仕組みです。
なお、プッシュ通知はオフラインでは届きません。ネットにつながっている状態であれば、ブラウザやアプリを閉じていても通知が届く仕組みです。
Service Workerを使っているサービス
Service Workerは多くの有名なサービスで使われています。
PWA
PWA(ピーダブルエー)とは、WebサイトをiOSアプリやAndroidアプリのように使えるようにする技術のことです。
PWAを実現する技術の一つとしてService Workerが使われています。なお、PWAを使った有名サービスには以下のようなものがあります。(ほんの一例です)
Google Maps
Google MapsのPWA版は、Service Workerの代表的な事例です。
Service Workerが、ユーザーが過去に閲覧した地図データをキャッシュします。これにより、インターネット接続がない状態でも、ある程度の範囲で地図を閲覧したり、ルート案内を利用したりできます。
頻繁に表示される地図タイル(地図の断片画像)をキャッシュすることで、ページの再読み込み時に高速に地図を表示します。
Starbucks
スターバックスのウェブサイトはPWA化されており、モバイル注文をより便利にしています。
Service Workerがメニューや価格情報をキャッシュします。これにより、インターネット接続がなくても、メニューを確認し、オフラインで注文をキューに入れることができます。接続が回復すると、自動的に注文が送信されます。
ブラウザのUIがないフルスクリーン表示により、ユーザーはネイティブアプリを使っているかのような感覚で注文できます。
Spotify
音楽ストリーミングサービスのSpotifyも、PWAを採用しています。
Service Workerが一部の音楽やアルバムのアートワークをキャッシュし、オフラインでも再生可能にします。ページ間の移動が速くなり、ユーザーがスムーズにコンテンツを探索できるようになります。
Google Chrome オフライン時の恐竜ゲーム
Google Chromeの有名なオフライン時に表示される恐竜ゲームも、Service Workerが裏側で動いています。
ネットワーク接続がない場合、Service Workerがゲームのデータをキャッシュから提供するため、インターネットがなくてもゲームをプレイできます。
Chrome拡張機能のバックグラウンド処理
一部のChrome拡張機能でもService Workerが使われることがあります。
これにより、拡張機能はブラウザを閉じた後もバックグラウンドで動作し、プッシュ通知の受信やデータの同期といったタスクを実行できます。
横取り(傍受)とキャッシュ戦略
Service Workerの横取り(傍受)とは?
通常のWebサイトでは、ユーザーがブラウザでURLにアクセスすると、ブラウザが「データ(画像、CSS、ウェブページ自体など)をください」というリクエスト(要求)を、インターネットを通じてサーバーに送ります。リクエストを受けて、サーバーが「レスポンス(応答・データ)」を返します。
【通常の流れ】
ブラウザ(リクエスト)→ サーバー (レスポンス)→ ブラウザ
Service Workerは、この「リクエスト」と「レスポンス」の間に立つ特別なプログラム(JavaScriptのファイル)です。
Service Workerを使うと、ブラウザが送ったリクエストをサーバーに渡す前に横取りし、キャッシュしたデータを返すか、サーバーにデータを取りに行くかという選択をすることができます。
【Service Workerの流れ】
①キャッシュがある場合
ブラウザ(リクエスト)→ Service Worker(レスポンス) → ブラウザ
②キャッシュがない場合
ブラウザ(リクエスト)→ Service Worker(リクエスト) → サーバー(レスポンス)→ Service Worker(レスポンス) → ブラウザ
キャッシュ戦略
Service Workerはなんでもかんでもキャッシュして保存するわけではありません。データ量の多いWEBサイトをキャッシュすると保存容量が膨大になってしまいます。
そこで、「高速化したい」や「オフラインで使いたい」といった用途に合わせて何をキャッシュするかを決めます。
これを「キャッシュ戦略」といいます。
Service Workerの具体例
Service WorkerはJavaScriptファイルで記述します。通常ファイル名はsw.jsとされるのが一般的です(自由に変更できます)
sw.jsにService Workerの処理を記述し、そのファイルを別のJavaScriptファイルなどでWebサイトに読み込ませることで動作します。
例えば、Service Worker 本体(sw.js)は以下のように記述します。(※どちらもサンプルです。書き方はやりたい処理により様々です)
self.addEventListener('install', event => {
// 初回インストール時にキャッシュする
event.waitUntil(
caches.open('my-cache').then(cache => {
return cache.addAll(['/index.html', '/style.css', '/script.js']);
})
);
});
self.addEventListener('fetch', event => {
// ネット通信を横取りして、キャッシュを優先
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});上記のファイルをJavaScriptで読み込む処理を記述します。
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(() => console.log('Service Worker 登録成功'))
.catch(err => console.log('登録失敗', err));
}コード解説
Service Worker 本体(sw.js)
Service Workerは初回インストール時にどういう処理をするかと、インストール済みの場合にどういう処理をするかを記述します。
self.addEventListener('install', event => {
// 初回インストール時にキャッシュする
event.waitUntil(
caches.open('my-cache').then(cache => {
return cache.addAll(['/index.html', '/style.css', '/script.js']);
})
);
});
self.addEventListener('fetch', event => {
// ネット通信を横取りして、キャッシュを優先
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});installイベント
最初にインストールされたときに必要なファイルをキャッシュしておく」処理です。これで、オフラインでもそのファイルが使えるようになります。
self.addEventListener('install', event => { ... })
Service Worker が「初めてインストールされるとき」に動く処理を定義します。self は Service Worker 自身を指しています(JavaScriptのthisみたいなもの)。
event.waitUntil(...)
インストールが終わるまで待ってほしい処理を指定します。これをしないと「キャッシュ準備が終わる前にインストール完了!」となってしまう可能性がある。
caches.open('my-cache')
my-cache という名前のキャッシュ領域を作ります(なければ新規作成)。
cache.addAll([...])
指定したファイルをまとめてキャッシュに保存します。ここでは index.html, style.css, script.js を保存するようにしています。
fetchイベント
通信を横取りして、キャッシュがあればそれを返し、なければネットから取ってくる仕組みです。これによってオフラインでもキャッシュしたページを表示できます。
self.addEventListener('fetch', event => { ... })
ユーザーがページをリクエストしたときに呼びだす処理です。例えば、ページを読み込むときの index.html、画像、CSS など。
event.respondWith(...)
そのリクエストに対して「どう返事するか」を指定する。
caches.match(event.request)
リクエストされたものがキャッシュにあるか探す。
response || fetch(event.request)
response が存在すれば(=キャッシュにあるなら)、それを返す。もしキャッシュになければ、ネットワークから取得して返す。
Service Workerのファイルを読み込む
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(() => console.log('Service Worker 登録成功'))
.catch(err => console.log('登録失敗', err));
}if ('serviceWorker' in navigator)
navigator は「ブラウザに関する情報」が入っている特別なオブジェクトです。その中に serviceWorker という機能があるかどうかをチェックしています。
古いブラウザには対応していない場合があるので確認をする処理です。
navigator.serviceWorker.register('/sw.js')
ブラウザに「sw.js」をService Workerとして登録依頼する処理です。'/sw.js' は Service Worker の本体ファイルへのパスです。
指定された /sw.js ファイルが存在すればサーバーからダウンロードします。エラーがなければ登録完了となります。
指定されたファイルが存在しなかったり、通信がHTTPS じゃなければセキュリティのためエラーになります。
Service Workerの登録処理が走ると、ブラウザがダウンロードして、ローカルに保存するのですが、ユーザーが直接触れる ダウンロードフォルダではなく、ブラウザ内部の専用領域に保存します。
★Chromeの場合は、Chrome の 「DevTools → Application → Service Workers」で確認できます。

ブラウザ内部の「Service Worker 用ストレージ」に保存され、必要なときに読み込まれます。次回アクセス時も再ダウンロードせず、保存された sw.js を使います(ただしファイルが更新されていれば差し替えます)。
.then(() => console.log('Service Worker 登録成功'))
sw.jsをService Workerとしての登録がうまくいったら、この処理が動きます。今回はただ「成功!」とログを出すだけ。
.catch(err => console.log('登録失敗', err))
sw.jsをService Workerとしての登録に失敗した場合の処理です。ここではエラーの内容をログに出すだけです。
例えば、ファイル名の間違いやHTTPSでないときにエラーとなりこの処理を実行します。
キャッシュを削除してもService Workerは消えない
ブラウザのキャッシュを削除した場合、Service Workerがキャッシュしたデータは削除されますが、Service Workerの元ファイル(例sw.js)は消えません。
Service Workerはキャッシュとは別の保存領域に保存されます。
★Chromeの場合は、Chrome の 「DevTools → Application → Storage」で確認できます。

キャッシュしたファイルは上記の「Chache storage」に入っています。


