Service Worker を使ってみた

# この記事は？
Service Workerでキャッシュを制御する方法について試してみたので内容をまとめてみました。
Service Workerを使用してPush通知等も可能になるとのことですが、今回はキャッシュ制御の部分だけを試してみようと思います。

# 作成したソースコード
作成したソースコードは[こちら](https://github.com/KiharaTakahiro/test_service_woker)にありますのでご自由に使用してください。
作成するファイルについては以下の通りです。

* index.html  
 Service Workerを使用するページのhtmlです。このページ内で表示する画像やjsに対してService Workerを使用してキャッシュの制御を行います。

``` html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="/test_servicewoker/index.js"></script>
    <title>Service Worker Test</title>
</head>
<body>
    <h1>Service Worker Test</h1>
    <img src="/test_servicewoker/my.png">
</body>
</html>
```
* index.js  
 index.htmlで使用されるjsです。「登録」することでService Worker がクライアントにダウンロードされるため登録するためのロジックを記載する必要があります。  
※`/test_servicewoker`となっている部分はドキュメントルートに`test_serviceworker`というディレクトリを作成して配置しているため記載しています。適宜読み替えてください。

```js
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/test_servicewoker/my-service-worker.js', { scope: '/test_servicewoker/' })
  .then(function(reg) {
    console.log('登録に成功しました。 Scope は ' + reg.scope);
  }).catch(function(error) {
    console.log('登録に失敗しました。' + error);
  });
}
```

* my-service-worker.js  
Service Workerの処理が記載されている場所です。  
※`/test_servicewoker`となっている部分はドキュメントルートに`test_serviceworker`というディレクトリを作成して配置しているため記載しています。適宜読み替えてください。

```js
const version = 'v2';
const CACHE_LIST = [
  '/test_servicewoker/index.html',
  '/test_servicewoker/index.js',
  '/test_servicewoker/my.png',
];

/**
 * キャッシュを対象の登録ロジック
 * 
 */
self.addEventListener('install', (event) => {
  console.log('run install');
  event.waitUntil(
    caches.open(version).then((cache) => {
      return cache.addAll(CACHE_LIST);
    })
  );
});

/**
 * 削除する処理が必要な場合に記載する
 * 
 */
 self.addEventListener('activate', (event) => {
  console.log('run activate');
  event.waitUntil(
    caches.keys().then((keyList) => {
      return Promise.all(keyList.map((key) => {
        if (version.indexOf(key) === -1) {
          console.log(key)
          return caches.delete(key);
        }
      }));
    })
  );
});

/**
 * キャッシュ対象の取得するか否かを判定して返す
 * 
 */
self.addEventListener('fetch', (event) => {
  console.log('run fetch');
  event.respondWith(
    caches.match(event.request).then((cacheResponse) => {
      return cacheResponse || fetch(event.request).then((response) => {
        return caches.open(version).then((cache) => {
          cache.put(event.request, response.clone());
          return response;
        });  
      });
    })
  );
});
```

* pngファイル  
二つ存在していますが、Service Workerの検証に使用するため2つあった方が良いと考えて用意しました。今回の検証では1つしか使用しませんが、個人的に確認したい内容があればぜひ試してみてください。

# 動作検証
xamppを使用してローカルにファイルを配置して確認を行いました。
index.htmlに対して初期表示させたのちに**「F5」**を何度か押してページ更新した場合にどのように動くのかをログをもとに確認しました。

* 初期表示

| ![1回目.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524088/117a4638-b804-1fff-8bc9-c4a6b0805ee6.png) |
|:--|

* ページ更新1回目


| ![2回目.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524088/0b7f0b19-c7b0-dcce-dace-440843c8935a.png) |
|:--|


* ページ更新2回目

| ![3回目.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524088/bb67a2b1-b582-75b7-acb4-9632ef101f1c.png) |
|:--|

# 検証から分かること
初回表示時にはfetchは動かず2回目の表示時にFetchが動きその後はFetchも動かなくなるようでした。
このことから考えてみる初回ページ表示時はService Workerはまったく動かず2回目の表示時にfetchが動くことでキャッシュに追加されて、3回目以降はキャッシュを利用して表示するのかなと思います。
試してみて気になったポイントではあったもののどこにも強調して書かれてなかったので少しまとめてみました。

# おわりに
今回は実際に動かしてみて気づいたことを中心にまとめてみました。ライフサイクル等の重要な点がほかにあることは分かるもののそれらの情報はほかでもたくさんまとめられているので今回はあえて書いておりません。
今後はpush通知などの他の使用方法についても触っていけたらなと考えています。

# 参考
これらの記事を参考に記載しております。
https://developer.mozilla.org/ja/docs/Web/API/Service_Worker_API
https://webbibouroku.com/Blog/Article/serviceworker!