こんにちは、インフラエンジニアの赤倉です。
今回は「ServiceWorker」のオフラインキャッシュを使ってWebページの読み込み高速化を実現してみたいとおもいます。
ServiceWorkerとは
ServiceWorker とは、ブラウザが Web ページとは別にバックグラウンドで実行するJavaScript環境のことです。ページ内のコンテンツをブラウザ側にキャッシュしてオフライン状態でも利用することができます。
対応ブラウザ
また、ServiceWorkerの稼働条件としてWebページのHTTPS化が必須となっております。(またはlocalhostでも実行可)
ServiceWorkerのライフサイクル
register
- ブラウザにServiceWorkerのJavaScriptファイルのパスを知らせます。
- ServiceWorkerが操作できるスコープ(後述)を指定します。
install
- ブラウザにキャッシュが生成されます。
- キャッシュ名(=バージョン)の定義やキャッシュ対象を指定します。
activate
- ServiceWorkerのJavaScriptファイルを更新します。 ServiceWorkerはサーバ上のJavaScriptファイルとバイト単位で差が生じた場合に新しいファイルと認識します。
- ユーザがブラウザを閉じたり、ページを更新したことを契機にServiceWorkerが更新されます。
スコープとは
ServiceWorker が管理するURLの範囲を示します。
スコープはServiceWorkerのスクリプトファイルが設置されているパス以下の階層を指定する必要があります。なお、このパス制限はService-Worker-Allowed: ヘッダで解除可能です。
ServiceWorker 導入
前置きが長くなってしまいましたが、ここからが導入手順になります。
準備するファイル
DocumentRoot ├── main.js ├── serviceworker.js
今回はどちらのファイルもDocumentRootに配置するものとします。
ファイル名に特に制約はありません。
1. ファイル作成
main.js
registerを行うファイルです。serviceworker.jsのパスを示します。
if ("serviceWorker" in navigator) { window.addEventListener("load", function () { //今回はDocRoot以下をServiceWorkerのスコープとします navigator.serviceWorker.register("/serviceworker.js", { scope: "./" }).then( function (registration) { // 登録成功 console.log( "ServiceWorker registration successful with scope: ", registration.scope ); }, function (err) { // 登録失敗 console.log("ServiceWorker registration failed: ", err); } ); }); }
serviceworker.js
ServiceWorkerのコアファイルです。※コードの細かい説明は省略します。
//キャッシュ名(=バージョン)を指定する
var CACHE_NAME = "cache-v1";
//キャッシュするファイル or ディレクトリを指定する
var urlsToCache = [ "/", ]; // install self.addEventListener("install", function (event) { event.waitUntil( caches.open(CACHE_NAME).then(function (cache) { console.log("Opened cache"); return cache.addAll(urlsToCache); }) ); }); // activate self.addEventListener("activate", function (event) { var cacheWhitelist = [CACHE_NAME]; event.waitUntil( caches.keys().then(function (cacheNames) { return Promise.all( cacheNames.map(function (cacheName) { if (cacheWhitelist.indexOf(cacheName) === -1) { return caches.delete(cacheName); } }) ); }) ); }); // fetch self.addEventListener("fetch", function (event) { event.respondWith( caches.match(event.request).then(function (response) { if (response) { return response; } var fetchRequest = event.request.clone(); return fetch(fetchRequest).then(function (response) { if (!response || response.status !== 200 || response.type !== "basic") { return response; } var responseToCache = response.clone(); caches.open(CACHE_NAME).then(function (cache) { cache.put(event.request, responseToCache); }); return response; }); }) ); });
2. main.js読み込み
ページの共通ヘッダなどに記載します。
<script src="/main.js"></script>
導入後の動作チェック
ServiceWorkerが動作していることはブラウザから確認可能です。
下記はGoogleChromeの検証モードの画面です。
[Status Code]に"(from service worker)"と記載されていればオフラインキャッシュ化成功です。
また、[Application]の[Service Woerkers]でも動作していることが確認できます。
効果
今回の検証では100MBの画像を読み込んだページでオフラインキャッシュの効果を試してみました。
ServiceWorkerなしの状態では画像の読み込みに852msかかっていますが・・
これがServiceWorkerのオフラインキャッシュを利用すると249msまで短縮されていることがわかります。
この検証はローカルのMAMP環境で実施したので読み込み時間にそこまで大きな差はありませんが、本番サーバであればもっと顕著に効果が出るとおもいます。
さいごに
ServiceWorkerを使ってオフラインキャッシュを作ることによって、画像やcss、 jsファイルなどの静的コンテンツの読み込みをコストゼロで高速化することができるので、非常に便利ですね。コストや技術的な理由でキャッシュサーバを用意できない場合などに導入を検討してみては如何でしょうか?
株式会社Wizではエンジニアを募集しています!
↓↓↓興味ある方はぜひご覧ください!↓↓↓