Sposób myślenia skryptu service worker

Jak myśleć o usługach w tle.

Roboty usługowe są potężne i absolutnie warto się ich nauczyć. Dzięki nim możesz zapewnić użytkownikom zupełnie nowe wrażenia. Witryna może wczytywać się natychmiast. Może działać offline. Można ją zainstalować jako aplikację specyficzną dla danej platformy, a zarazem zapewnia doskonałą jakość, a jednocześnie zapewnia swobodę i zasięg internetu.

Jednak service worker różni się od tego, do czego przywykli programiści. Ich nauka jest trudna, a trzeba uważać na kilka pułapek.

Niedawno współpracowałem z Google Developers nad projektem Service Workies, czyli darmową grą, która pomaga zrozumieć skrypty service worker. Podczas tworzenia i używania złożonych funkcji service workerów napotkałem na kilka problemów. Najbardziej pomogło mi wymyślanie metafor. W tym poście przyjrzymy się tym modelom mentalnym i spróbujemy zrozumieć paradoksalne cechy, które sprawiają, że pracownicy usług są jednocześnie trudni i świetni.

To samo, ale inaczej

Podczas kodowania serwisowego workera wiele rzeczy może wydawać się znajomych. Możesz korzystać z ulubionych nowych funkcji języka JavaScript. Zdarzenia cyklu życia nasłuchujesz tak samo jak zdarzenia UI. Zarządzasz przepływem sterowania za pomocą obietnic, tak jak do tej pory.

Ale inne zachowania skryptu service worker powodują, że przeczesujesz zdezorientowany głową. Zwłaszcza wtedy, gdy po odświeżeniu strony nie widzisz wprowadzonych zmian w kodzie.

nowa warstwa,

Podczas tworzenia witryny zwykle trzeba się zajmować tylko 2 poziomami: klientem i serwerem. Usługa w tle to zupełnie nowa warstwa, która znajduje się pośrodku.

Pracownik usługi działa jako pośrednik między klientem a serwerem

Skrypt service worker jest swego rodzaju rozszerzeniem do przeglądarki – możesz je zainstalować w przeglądarce użytkownika. Po zainstalowaniu pracownik usługi rozszerza przeglądarkę Twojej witryny o potężną warstwę pośrednią. Ten poziom usługi może przechwytywać i obsługiwać wszystkie żądania wysyłane przez Twoją witrynę.

Warstwa skryptu service worker ma własny cykl życia niezależny od karty przeglądarki. Proste odświeżenie strony nie wystarcza do zaktualizowania skryptu service worker – tak samo jak nie spodziewasz się, że odświeżenie strony zaktualizuje kod wdrożony na serwerze. Każda warstwa ma własne reguły aktualizacji.

W grze Service Workies omawiamy wiele szczegółów cyklu życia usługi i zapewniamy Ci mnóstwo okazji do pracy z tą usługą.

Potężne, ale ograniczone

Umieszczenie w witrynie mechanizmu Service Worker daje ogromne korzyści. Witryna może:

Mimo że workery usługowe mogą wiele, są one ograniczone ze względu na swoją konstrukcję. Nie mogą wykonywać żadnych działań synchronicznie ani w tym samym wątku co Twoja witryna. Oznacza to, że nie masz dostępu do tych funkcji:

  • localStorage
  • DOM
  • okno

Dobra wiadomość jest taka, że strona może komunikować się z usługą w kilka sposobów, m.in. bezpośrednio postMessage, za pomocą kanałów wiadomości jeden-do-jednego i kanałów rozgłoszeniowych jeden-do-wielu.

długotrwałe, ale krótkotrwałe

Aktywny service worker działa nawet wtedy, gdy użytkownik opuści Twoją witrynę lub zamknie kartę. Przeglądarka przechowuje ten skrypt service worker, aby był gotowy, gdy użytkownik wróci do witryny. Zanim zostanie wysłane pierwsze żądanie, skrypt service worker może je przechwycić i przejąć kontrolę nad stroną. Dzięki temu witryna może działać w trybie offline – skrypt service worker może wyświetlić wersję strony z pamięci podręcznej, nawet jeśli użytkownik nie ma połączenia z internetem.

W narzędziu Service Workies wizualizujemy tę koncepcję za pomocą usługi Kolohe (przyjaznej usłudze Service Workies), która przechwytuje i obsługuje żądania.

Zatrzymano

Mimo że instancje robocze wydają się nieśmiertelne, można je zatrzymać niemal w każdej chwili. Przeglądarka nie chce marnować zasobów na skrypt service worker, który nic nie robi. Zatrzymanie nie jest tym samym co zakończenie – usługa robocza pozostaje zainstalowana i aktywna. Urządzenie jest tylko uśpione. Gdy będzie to potrzebne (np. do obsługi żądania), przeglądarka ponownie uruchomi proces.

waitUntil

Ze względu na ciągłą możliwość przejścia w tryb uśpienia Twój serwis worker musi mieć możliwość poinformowania przeglądarki, że wykonuje coś ważnego i nie chce zasnąć. Właśnie tutaj do akcji wkraczają event.waitUntil(). Ta metoda wydłuża cykl życia, w którym jest używana, dzięki czemu nie można jej zatrzymać, ani przejść do następnego etapu cyklu życia, dopóki nie wszystko będzie gotowe. To daje nam czas na skonfigurowanie pamięci podręcznych, pobranie zasobów z sieci itd.

Ten przykład informuje przeglądarkę, że skrypt service worker nie zakończy się, dopóki pamięć podręczna assets nie zostanie utworzona i wypełniona obrazkiem miecza:

self.addEventListener("install", event => {
  event.waitUntil(
    caches.open("assets").then(cache => {
      return cache.addAll(["/weapons/sword/blade.png"]);
    })
  );
});

Uwaga na stan globalny

Gdy nastąpi uruchomienie lub zatrzymanie, zasięg globalny pracownika usługi zostanie zresetowany. Uważaj, aby nie używać w usługach workera żadnych stanów globalnych, bo następnym razem, gdy usługa zostanie uruchomiona, może mieć stan inny od oczekiwanego.

Rozważ ten przykład, który używa stanu globalnego:

const favoriteNumber = Math.random();
let hasHandledARequest = false;

self.addEventListener("fetch", event => {
  console.log(favoriteNumber);
  console.log(hasHandledARequest);
  hasHandledARequest = true;
});

W przypadku każdego żądania ten proces roboczy zapisuje liczbę, np. 0.13981866382421893. Zmienna hasHandledARequest również zmieni się na true. Teraz usługa nieczynnie działa przez chwilę, więc przeglądarka ją zatrzymuje. Przy następnym żądaniu skrypt service worker jest potrzebny ponownie, więc przeglądarka wybudza go. Jego skrypt jest ponownie oceniany. Teraz hasHandledARequest to false, a favoriteNumber to coś zupełnie innego – 0.5907281835659033.

Nie możesz polegać na zapisanym stanie w skrypcie service worker. Tworzenie instancji takich rzeczy jak kanały wiadomości może też powodować błędy: za każdym razem, gdy usługa robocza przestanie działać lub się uruchomi, będziesz mieć nową instancję.

rozdziale 3 książki „Service Workers” zatrzymany skrypt service worker traci kolor, gdy czeka na powiadomienie.

wizualizacja zatrzymanego service workera

Razem, ale oddzielnie

Twoja strona może być sterowana tylko przez 1 skrypt service worker naraz. Może jednak zainstalować jednocześnie 2 usługi. Gdy wprowadzisz zmiany w kodzie usługi i odświeżysz stronę, nie edytujesz w ogóle usługi. Usługa robocza jest niezmienna. Zamiast tego tworzysz coś zupełnie nowego. Ten nowy serwis worker (nazwijmy go SW2) zostanie zainstalowany, ale nie zostanie jeszcze aktywowany. Musi zaczekać, aż bieżący pracownik usługi (SW1) zakończy działanie (gdy użytkownik opuści witrynę).

modyfikowanie pamięci podręcznej innego workera usługi;

Podczas instalacji SW2 może skonfigurować niektóre elementy, zwykle tworząc i wypełniając pamięci podręczne. Pamiętaj jednak, że ten nowy skrypt service worker ma dostęp do wszystkich elementów, do których ma dostęp aktualny skrypt service worker. Jeśli nie będziesz uważać, nowy skrypt service worker w stanie oczekiwania może zepsuć działanie bieżącego skryptu service worker. Przykłady, które mogą sprawiać problemy:

  • SW2 może usunąć pamięć podręczną, z której aktywnie korzysta SW1.
  • SW2 może edytować zawartość pamięci podręcznej, której używa SW1, co spowoduje, że SW1 odpowie komponentami, których strona nie oczekuje.

Pomiń skipWaiting

Skrypt service worker może też używać ryzykownej metody skipWaiting(), aby przejąć kontrolę nad stroną zaraz po zainstalowaniu. Zazwyczaj nie jest to dobry pomysł, chyba że celowo chcesz zastąpić usługę workera, która ma błędy. Nowy serwis worker może używać zaktualizowanych zasobów, których nie oczekuje bieżąca strona, co może powodować błędy.

Zacznij od zera

Aby zapobiec wzajemnemu blokowaniu się przez service workery, upewnij się, że używają różnych pamięci podręcznych. Najprostszym sposobem jest utworzenie wersji nazw używanych przez nie nazw pamięci podręcznej.

const version = 1;
const assetCacheName = `assets-${version}`;

self.addEventListener("install", event => {
  caches.open(assetCacheName).then(cache => {
    // confidently do stuff with your very own cache
  });
});

Gdy wdrożysz nowy skrypt service worker, zwiększysz wartość version, aby wykonywał on swoje zadania w zupełnie oddzielnej pamięci podręcznej od poprzedniego skryptu service worker.

wizualizacja pamięci podręcznej

Sprzątanie po zakończeniu

Gdy usługa osiągnie stan activated, wiesz, że przejęła kontrolę, a poprzednia usługa jest zbędna. W tym momencie ważne jest, aby uporządkować stare workery usług. Nie tylko uszanuje limity miejsca na dane w pamięci podręcznej użytkowników, ale też może zapobiegać niezamierzonym błędom.

Metoda caches.match() to często używany skrót do pobierania elementu z każdej pamięci podręcznej, w której występuje dopasowanie. Przegląda jednak pamięci podręczne w kolejności ich utworzenia. Załóżmy, że masz 2 wersje pliku skryptu app.js w 2 różnych pamięciach podręcznych – assets-1assets-2. Strona oczekuje nowszego skryptu zapisanego w interfejsie assets-2. Jeśli jednak nie usuniesz starej pamięci podręcznej, caches.match('app.js') zwróci starszą wersję z assets-1 i prawdopodobnie uszkodzi Twoją witrynę.

Aby wyczyścić poprzednich pracowników usługi, wystarczy usunąć wszystkie dane z poziomu pamięci podręcznej, których nie potrzebuje nowy pracownik usługi:

const version = 2;
const assetCacheName = `assets-${version}`;

self.addEventListener("activate", event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (cacheName !== assetCacheName){
            return caches.delete(cacheName);
          }
        });
      );
    });
  );
});

Uniemożliwianie pracownikom usługowym ograniczania się nawzajem, wymaga trochę pracy i dyscypliny, ale warto się tym zająć.

Sposób myślenia o skryptach service worker

Gdy zaczniesz myśleć o skryptach service worker, zbudujesz własne nastawienie. Gdy opanujesz te narzędzia, będziesz mieć możliwość tworzenia niesamowitych treści dla użytkowników.

Jeśli chcesz zrozumieć wszystkie te informacje i grać w grę, masz szczęście! Graj w Service Workies, aby dowiedzieć się, jak za pomocą usług w tle pokonać potwory offline.