Sposób myślenia skryptu service worker

Jak myśleć o skryptach service worker.

Mechanizmy Service Worker mają duże możliwości i warto się ich nauczyć. Pozwalają zapewnić użytkownikom zupełnie nowy poziom obsługi. Witryna może wczytywać się od razu. Może działać offline. Można ją zainstalować jako aplikację specyficzną dla danej platformy, a zarazem zapewnia doskonałą jakość działania, a jednocześnie zapewnia swobodę i zasięg internetu.

Skrypty service worker różnią się jednak od tych, do których przyzwyczaiła się większość programistów internetowych. Wymagają sporo nauki i wymagają uważania na kilka problemów.

Niedawno razem z Google Developers pracowaliśmy nad projektem Service Workies – bezpłatnej gry ułatwiającej zrozumienie mechanizmów Service Workies. Podczas budowania go oraz pracy z zapleczem pracowników usługowych natknęło się na kilka problemów. Najbardziej pomogło mi to z kilkoma metaforami. W tym poście przyjrzymy się bliżej tym modelom psychicznym i wyjaśnimy paradoksalne cechy, które sprawiają, że pracownicy usługowi są nie tylko skomplikowani, ale też wspaniali.

Ta sama, ale inna

Podczas kodowania skryptu service worker wiele rzeczy może wydawać się znajomych. Możesz korzystać z ulubionych nowych funkcji języka JavaScript. Nasłuchujesz zdarzeń cyklu życia tak samo jak w przypadku zdarzeń interfejsu. Zarządzasz przepływem pracy, korzystając z obietnic podobnych do tych, które znasz.

Jednak inne zachowania mechanizmu Service Worker sprawiają, że możesz czuć zakłopotanie. Zwłaszcza wtedy, gdy po odświeżeniu strony nie widzisz zmian w kodzie.

Nowa warstwa

Zazwyczaj podczas budowania witryny wystarczy rozważyć tylko dwie warstwy: klient i serwer. Skrypt service worker to zupełnie nowa warstwa znajdująca się pośrodku.

Skrypt service worker działa jako warstwa pośrednia 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 skrypt service worker rozszerza przeglądarkę witryny o zaawansowaną warstwę środkową. Ta warstwa skryptu service worker 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 spowoduje zaktualizowanie kodu wdrożonego na serwerze. Każda warstwa ma własne, unikalne reguły aktualizowania.

W grze Service Workies omawiamy wiele szczegółów cyklu życia mechanizmów Service Workies i zapewniamy Ci mnóstwo ćwiczeń podczas pracy z nimi.

Zaawansowane, ale ograniczone

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

Usługodawcy mają tyle możliwości, że są z założenia ograniczona. Nie mogą robić niczego synchronicznego ani w tym samym wątku co witryna. Oznacza to brak dostępu do:

  • localStorage
  • DOM
  • okno

Dobra wiadomość jest taka, że istnieje kilka sposobów komunikacji strony z mechanizmem Service Worker, w tym bezpośrednie postMessage, kanały wiadomości 1:1 i kanały naziemne jeden do wielu.

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

Aktywny skrypt service worker działa nawet po opuszczeniu witryny przez użytkownika lub zamknięciu karty. Przeglądarka przechowuje ten skrypt service worker, aby był gotowy, gdy użytkownik wróci do witryny. Przed wysłaniem pierwszego żądania mechanizm Service Worker ma szansę je przechwycić i przejąć kontrolę nad stroną. To właśnie umożliwia działanie witryny 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

Chociaż mechanizmy Service Worker 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 obecnie nic nie robi. Zatrzymanie to nie to samo, co zakończenie – skrypt service worker pozostaje zainstalowany i aktywowany. Zostało ono właśnie uśpione. Gdy następnym razem będzie to potrzebne (np. w celu przetworzenia żądania), przeglądarka ponownie je wybudzi.

waitUntil

Ciągle użytkownik może zasnąć, dlatego pracownik usługi musi mieć sposób na poinformowanie przeglądarki o tym, że wykonuje coś ważnego i że nie chce ucinać sobie drzemki. Właśnie tutaj do akcji wkracza 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 jej 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"]);
    })
  );
});

Uważaj na stan globalny

Gdy następuje uruchomienie/zatrzymanie, globalny zakres skryptu service worker jest resetowany. Uważaj więc, aby nie używać żadnego stanu globalnego w skrypcie service worker. W przeciwnym razie, gdy następnym razem urządzenie się obudzi, będzie w inny sposób niż oczekiwał, poczujesz smutek.

Przyjrzyjmy się temu przykładowi, w którym użyto stanu globalnego:

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

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

Przy każdym żądaniu ten skrypt service worker zapisze liczbę – powiedzmy 0.13981866382421893. Zmienna hasHandledARequest zmienia się też na true. Teraz skrypt service worker przez jakiś czas jest nieaktywny, więc przeglądarka go 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 teraz false, a favoriteNumber to coś zupełnie innego – 0.5907281835659033.

W skrypcie service worker nie możesz polegać na stanie składowania. Również tworzenie instancji takich jak kanały wiadomości może powodować błędy: przy każdym zatrzymaniu/uruchomieniu skryptu service worker otrzymasz zupełnie nową instancję.

W rozdziale 3 Service Workies wizualizujemy zatrzymany skrypt service workies jako tracący wszystkie kolory, czekając na wybudzenie.

wizualizacja zatrzymanego skryptu service worker

Razem, ale oddzielnie

Stronę może w danym momencie kontrolować tylko jeden skrypt service worker. Można jednak zainstalować w niej 2 skrypty service worker jednocześnie. Gdy zmienisz kod skryptu service worker i odświeżysz stronę, w rzeczywistości nie edytujesz go. Skryptów service worker nie można zmienić. Zamiast tego tworzysz coś zupełnie nowego. Ten nowy skrypt service worker (nazwijmy go SW2) zainstaluje, ale nie zostanie jeszcze aktywowany. Musi poczekać na zakończenie działania bieżącego skryptu service worker (SW1) (gdy użytkownik opuści witrynę).

Występowanie problemów z pamięciami podręcznymi innego skryptu service worker

Podczas instalacji SW2 może przeprowadzić konfigurację – zwykle tworzy i zapełnia 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 zachowasz ostrożności, nowy skrypt usługi czeka na błędy. Przykłady, które mogą sprawiać problemy:

  • Oprogramowanie SW2 może usunąć pamięć podręczną, której aktywnie używa SW1.
  • Oprogramowanie SW2 może edytować zawartość pamięci podręcznej używanej przez SW1, co spowoduje, że SW1 prześle w odpowiedzi zasoby, których strona się nie spodziewała.

Pomiń czekanie

Skrypt service worker może też wykorzystać ryzykowną metodę skipWaiting(), aby przejąć kontrolę nad stroną zaraz po zakończeniu instalacji. Nie jest to zwykle dobry pomysł, chyba że celowo próbujesz zastąpić nieprawidłowy skrypt usługi. Nowy skrypt service worker może używać zaktualizowanych zasobów, których nie oczekuje bieżąca strona, co może powodować błędy.

Zacznij czyszczenie

Aby uniemożliwić mechanizmy Service Worker z dublowaniem siebie nawzajem, upewnij się, że używają różnych pamięci podręcznych. Najprostszym sposobem, aby to osiągnąć, jest zmiana wersji 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
  });
});

Podczas wdrażania nowego skryptu service worker version zmienisz tak, aby działał on z całkowicie odrębną pamięcią podręczną od poprzedniego mechanizmu.

wizualizacja pamięci podręcznej

Zakończ sprzątanie

Gdy skrypt service worker osiągnie stan activated, będziesz wiedzieć, że został przejęty, a poprzedni skrypt service worker jest nadmiarowy. W tym momencie należy wyczyścić dane po starym mechanizmie Service Worker. Szanuje ona nie tylko pamięci podręcznej, ale może też zapobiec 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. Korzysta jednak z pamięci podręcznych w kolejności, w jakiej zostały utworzone. Załóżmy więc, że masz 2 wersje pliku skryptu app.js w 2 różnych pamięciach podręcznych – assets-1 i assets-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 starą wersję z usługi assets-1, co najprawdopodobniej spowoduje uszkodzenie Twojej witryny.

Aby wyczyścić dane po poprzednim mechanizmach Service Worker, wystarczy usunąć pamięć podręczną, której nowy skrypt nie potrzebuje:

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ę wzajemnie wymaga pracy i dyscypliny, ale warto się napracować.

Postawa na mechanizm Service Worker

Gdy zaczniesz myśleć o skryptach service worker, zbudujesz własne nastawienie. Kiedy już się na nich nauczysz, będziesz w stanie tworzyć dla użytkowników niesamowite funkcje.

Jeśli chcesz zrozumieć wszystkie te informacje i grać w grę, masz szczęście! Przejdź do gry Service Workies, w której poznasz sposoby mechanizmu Service Workies do zabijania offline bestii.