サービスワーカー

この記事では、サービスワーカー(SW)についてお話したいと思います。SWを使用すると、アプリケーションをオフラインで動作できるようにすることができるため、インターネットに接続していなくても動作します。また、プッシュ通知やバックグラウンド同期など、他の多くの高度な機能を使用することもできます。SWは、ブラウザを閉じた後も実行を継続します。つまり、ServiceWorkerは実行を継続します。これはバックグラウンドプロセスです。それでは、最初のServiceWorkerを登録しましょう。





(この記事では、SW関連の機能をプレーンJSに実装します。コードはプレーンJSで記述されているため、Angular、React、VueなどのJSフレームワークに統合できます)





最初のステップとして、sw.jsファイルをプロジェクトのルートに追加します。app.jsでは、SWがナビゲーターで使用可能かどうか、つまりSWがこのブラウザーでサポートされているかどうかを確認する必要があります。SWが使用可能であることがわかったので、navigator.serviceWorker.register()メソッドを実行して、SWが存在するファイルへのパスを指定して登録できます。このメソッドは実際にはPromiseを返します。ですから、情報を得るために、それが終わったら、私たちは彼に加わることができます。





if ('serviceWorker' in navigator) {
  navigator.serviceWorker
    .register('/sw.js')
    .then(event => {
      console.log('Service worker registered', event);
    });
}
      
      



SW, . , SW . , . SW, , , self, « SW», addEventListener (). SW , , , , Service Worker’a. , , . , Service Worker .





self.addEventListener('install', event => {
  console.log('Installing [Service Worker]', event);
});
      
      



. Service Worker’a - , , . caches, API , open (), . , . event.waitUntil (). , . . then . cache.addAll () , .





self.addEventListener('install', event => {
  console.log('Installing [Service Worker]', event);

  event.waitUntil(
    caches.open('static')
      .then(cache => {
        console.log('[Service Worker] Precaching App Shell');
        cache.addAll([
          '/',
          '/index.html',
          '/favicon.ico',
          '/src/js/app.js',
          '/src/js/chart.js',
          '/src/js/materialize.js',
          '/src/js/materialize.min.js',
          '/src/css/materialize.css',
          '/src/css/materialize.min.css',
          '/src/css/style.css',
          'https://fonts.googleapis.com/icon?family=Material+Icons',
          'https://code.jquery.com/jquery-2.1.1.min.js',
          'https://cdn.jsdelivr.net/npm/chart.js@2.8.0'
        ]);
      }));
});
      
      



, -.









, . , . , , - . Fetch , - - , css js xhr. , fetch Service Worker’a , . , , .





self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        if (response) {
          return response;
        } else {
          return fetch(event.request);
        }
      })
    );
});
      
      







event.respondWith () , . Service Worker’ , , fetch. , Service Worker, . , , . cashes.match () , . , . , , , , , , . , , , , fetch (event.request). - . 









, - , « » . , , , . , . , . , , , . , .






    Object.keys(pureData).forEach(key => tmp[sorter[key.toLowerCase()]] = { key, value: pureData[key] });

    tmp.forEach(obj => orderedData[obj.key] = obj.value);

    const ctx = document.getElementById('myChart').getContext('2d');

    new Chart(ctx, {
      type: 'line',
      data: {
          labels: Object.entries(orderedData).map(([key, _]) => key),
          datasets: [{
              label: 'Users',
              backgroundColor: '#26a69a',
              borderColor: '#26a69a',
              fill: false,
              data: Object.entries(orderedData).map(([_, value]) => value),
          }]
      }
    });
  });
};
      
      







, , , .





self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        if (response) {
          return response;
        } else {
          return fetch(event.request)
            .then(res => {
              return caches.open('dynamic')
                .then(cache => {
                  cache.put(event.request.url, res.clone());
                  return res;
                })
            });
        }
      })
    );
});
      
      







, , , . , caches, API open (), . cache.put () , . , , - URL- , . - . , , , , . . . . xhr. , css .









. - , . ? SW . , - , , , , indexedDB. , , SW . SW, . , , . , , Service Worker’y . , . - , , API, . Service Worker’y, ready, , . , . , ( ), . , , . , « ». Service Worker’, , , , , .





if ('serviceWorker' in navigator && 'SyncManager' in window) {
      navigator.serviceWorker.ready
        .then(sw => {
          sw.sync.register('sync-request')
        });
    }
      
      







, «POST DATA» , , indexedDB . , indexedDB. , . . - . «sunday», 10 ( :)). writeData utility.js, . - , , - . .





const syncButton = document.getElementById('sync-button');

syncButton.addEventListener('click', _ => {
    if ('serviceWorker' in navigator && 'SyncManager' in window) {
      navigator.serviceWorker.ready
        .then(sw => {
          const data = {
            id: new Date().getTime(),
            sunday: 10
          };

          writeData('sync-requests', data)
            .then(_ => {
              sw.sync.register('sync-request')
            });
        });
    }
});
      
      







, , - . , , .





self.addEventListener('sync', event => {
  console.log('[Service Worker] Syncing');

  if (event.tag === 'sync-request') {
    event.waitUntil(
      readAllData('sync-requests')
        .then(async data => {
          const requests = [];

          for (const d of data) {
            requests.push(fetch('https://simple-pwa-8a005.firebaseio.com/data.json', {
              method: 'POST',
              headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json'
              },
              body: JSON.stringify({
                sunday: d.sunday
              })
            }));
          }

          const results = await Promise.all(requests);

          results.map((response, index) => {
            if (response.ok) {
              deleteItemFromData('sync-requests', data[index].id);
            }
          })
        })
    );
  }
});
      
      



. event.waitUntil (), , , . , indexedDB ( utility.js), , post , indexedDB, . . . , , «POST DATA» .





「POSTDATA」ボタンを押した後、オフラインのときは何も起こりませんが、接続が復元されると、同期が完了したことがわかります。









また、データが実際にサーバーに送信されたことを確認するには、最初に動的キャッシュからフェッチ要求を削除して、[データの取得]ボタンをクリックする必要があります。 









それは今のところすべてです。じゃあまたね。私のコードはgithubで入手できます:https://github.com/Draakan/simplePWA








All Articles