JavaScript
ServiceWorker

ServiceWorkerを触ってみる

More than 1 year has passed since last update.

https://dev.to/mizchi/-devto--b5
の記事を読んでServiceWorkerってどんな仕組みなんだろうということが気になって調べてみました。

https://developers.google.com/web/fundamentals/primers/service-workers/?
によると
- domは触れない
- ネットワークプロキシ的なことがコードで書ける

らしいです。なのでAPIのレスポンスをネットワークアクセスなしにキャッシュしたりできると。
ほぼ参考文献ままですがコード書いてみました。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <h1>sw test</h1>

    <input id="url" type="text" name="" value="">
    <button id="add" type="button" name="button">add</button>
    <div id="list">
    </div>
    <script type="text/javascript">
    if ("serviceWorker" in navigator) {
      navigator.serviceWorker.register("/sw.js").then(function(registration) {
        console.log("success", registration.scope);
      }).catch(function(err) {
        console.log("error", err);
      });
    }

    var addBtn = document.querySelector("#add");
    addBtn.addEventListener("click", function() {
      var url = document.querySelector("#url").value;
      fetch("/resp/"+url)
      .then(function(resp) {
        return resp.json();
      })
      .then(function(data) {
        html = "";
        data.list.forEach(function(item) {
          html += "<p>"+item.name+"</p>";
        });
        document.querySelector("#list").innerHTML = html;
      });
    });
    </script>
  </body>
</html>
sw.js
var CACHE_NAME = "my-site-cache-v1";

self.addEventListener("fetch", function(event) {
  event.respondWith(
    caches.open(CACHE_NAME).then(function(cache) {
      return cache.match(event.request).then(function(resp) {
        if(resp) {
          return resp;
        }
        return fetch(event.request.clone()).then(function(resp) {
          if (resp.status<400 && (resp.url.indexOf("a.json")>=0)) {
            cache.put(event.request, resp.clone());
          }
          return resp;
        });
      });
    })
  );
});

respディレクトリ以下に以下の形式のjsonをモックとして置く

a.json
{
  "list": [
    {"name": "a1"},
    {"name": "a2"}
  ]
}

  1. navigator.serviceWorker.register でserviceWorkerの登録ができます。すでに登録されている場合はそれが使われる
  2. CACHE_NAMEの値をキーにしてAPIのレスポンスをキャッシュする。キャッシュする条件はレスポンスオブジェクトから好きに設定できる(今回の場合はa.jsonはしかキャッシュしないようにした
  3. API呼び出し側はキャッシュされているかどうかは気にせずレスポンスを使えばいい。なので、serviceWorkerが使えない場合でも正常に動く

上記を試したときのchrome devtoolのnetwork
image.png

枠で囲った部分が1リクエストあたりに表示される。a.jsonを取得するときには二回目以降は「from ServiceWorker」となっているが、b.jsonはsw.jsが取得してきたものが渡されている。sw.jsがAPIを呼び出すログも出力されているのでキャッシュされているかどうかを判断ここで判断できる(はず)。

参考文献