Service Worker一問一答


Service Worker
PWAの核心はサービスWorkerにあり、現在、中国語コミュニティではサービスWorkerに関する知識の深さが一般的に不足しており、実際のプロジェクトの問題に対応することは難しい.例えば、sw(以下、swと略称する)をアンインストールした後、cachesを手動でクリーンアップする必要があるかどうかを知りたいのですが、検索エンジンには良い答えはありません.この文章は淘宝のトップページPWAの経験と結びつけて、サービスWorkerに関する非常に価値のある知識点を共有しています.
まず登録から言えば、swはいつ登録すればいいですか?
いくつかのチュートリアルはこのようにswを登録します
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
}

これにより、swスレッドがCPUとメモリの使用を激化させ、sw内のプリキャッシュリソースがダウンロードされる必要があり、モバイルデバイスの帯域幅が限られており、swスレッドが占有されると、メインプロセスの帯域幅が小さな水道管になります.
さまざまなリソースを初めて開くことは貴重です.また、漸進的なので、最初にページを開いてリソースをキャッシュする必要はありません.正しいやり方は、ページをロードしてからswすることです.
if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('/sw.js');
  });
}

登録したすべてのユーザーのswを抹消したいのですが、どうすれば一番妥当ですか?
すべてのモバイルブラウザがgetRegistrationsをサポートしているわけではありません.getRegistrationの方が頼りになります.getRegistrationsを使用してみてください.使用できない場合はgetRegistrationを試してみてください.以下のようにします.
var serviceWorker = navigator.serviceWorker;

serviceWorker.getRegistrations ? serviceWorker.getRegistrations().then(function(sws) {
  sws.forEach(function(sw) {
    sw.unregister();
  });
}) : serviceWorker.getRegistration && serviceWorker.getRegistration().then(function(sw) {
  sw && sw.unregister();
});

私はswをログアウトしましたが、前に残したcachesは自分で処理する必要がありますか?
必要に応じて、cacheStorageはPWA仕様APIに属していますが、独立しています.service workerをログアウトしても、cachesのゴミが消えず、ずっとそこに残っています.こんなにはっきりしている
window.caches && caches.keys && caches.keys().then(function(keys) {
  keys.forEach(function(key) {
    caches.delete(key);
  });
});

selfを使用すべきかどうか.clients.claim?
clients.claimの役割は、現在のSWに開いているすべてのラベルページを引き継ぐことであり、使用シーンがユーザが登録swのページを初めて開いたときに、他の同ドメインページのブラウザラベルが存在する場合である.前に開いたページは引き継がれていないのでclients.claimは、すでに開いているが制御されていないブラウザラベルページを管理します.
skipWaitingの使用シーンはsw更新時で、前のswがすべてのサイトのページを制御しているため、新しいswはactive後にwaiting状態に入り、ユーザーがすべてのサイトのページを閉じるまで、新しいswが上位になります.これはChromeやVscodeの更新メカニズムと同様に、使用中に更新がある場合は、古いバージョンの使用を継続することに影響を与えるのではなく、プログラムを再起動した後、直接新しいバージョンになります.skipWaitingメソッドでは、waiting状態の新しいswを古いswに直接置き換えることができ、前のsw管轄のページを自動的に引き継ぐことに注意します.
私はclientsの使用をお勧めしません.claimの場合、まず制御されていないラベルが現れることは比較的少なく、しかも初回ロード速度が特に重要で、コストを節約できるなら節約しましょう.
swでfetchイベントを傍受して、リクエストがswより多くなったら、性能損失がありますか?
もちろん、次のようにするのは、絶対にいらない.
self.addEventListener('fetch', event => {
  event.respondWith(fetch(event.request));
});

どうして私はswの中でpostMessageがページに着いて、ページはmessageを受け取ることができません
これはサービスWorkerのpostMessage能力をテストするときによくある問題で、原因を見つけるにはswが引き継いだページから始めなければなりません.sw.jsではselfを用いる.clients.matchAllメソッドは、現在のserviceWorkerインスタンスが管理するすべてのラベルページを取得し、現在のインスタンスが管理されていることに注意し、sw.jsのコードはsw.jsコードに次のコードが存在する場合
self.clients.matchAll()
  .then(function (clients) {
    clients.forEach(client => {
      client.postMessage('         ');
    })
  });

Clientsは空の配列に違いないので、いつまでもpostMessageではページがありません.では、最初のinstallでpostMessageをページに表示するにはどうすればいいですか?答えはselfです.skipWaiting、activateイベントでselfを使用します.clients.matchAll、skipWaitingを呼び出したため、現在のswはinstall後すぐにavtivateして前のswのすべてのラベルページを引き継ぐことができて、このように新しいswの中でラベルページpostMessageを手に入れることができます
self.skipWaiting()
self.addEventListener('activate', () => {
  self.clients.matchAll()
    .then(function (clients) {
      clients.forEach(client => {
        client.postMessage('skipWaiting   sw     ,       ');
      })
    });
})