Sposób myślenia skryptu service worker

Jak myśleć o skryptach service worker.

Mechanizmy Service Worker dają wiele możliwości i naprawdę warto się ich nauczyć. Dzięki nim możesz zapewnić użytkownikom zupełnie nowy poziom obsługi. Witryna może się wczytywać od razu. Może działać offline. Można ją zainstalować jako aplikację przeznaczoną na konkretną platformę, a jej wrażenia będą dopracowane – ale w zasięgu i w swobodnym środowisku internetu.

Mechanizmy service worker różnią się jednak od innych rozwiązań, do których większość programistów stron internetowych jest przyzwyczajona. Mają one trudności z nauką i kilka haczyków, na które trzeba uważać.

Niedawno z Google Developers współpracowaliśmy nad projektem Service Workies – bezpłatnej gry umożliwiającej zrozumienie mechanizmów Service Workers. Podczas tworzenia go i pracy z innymi pracownikami serwisowymi napotkałam kilka problemów. Najbardziej pomogło mi wymyślenie kilku opisowych metafor. W tym poście przyjrzymy się tym modelom psychicznym i zapoznamy się z paradoksalnymi cechami, które sprawiają, że mechanizmy service worker są zarówno podstępne, jak i wspaniałe.

Ta sama, ale inna

Kodowanie skryptu service worker może wydawać się znajome. Teraz możesz korzystać z ulubionych nowych funkcji języka JavaScript. Nasłuchujesz zdarzeń cyklu życia tak samo jak w przypadku zdarzeń interfejsu. Zarządzasz procesem kontroli, obiecując obiecywanie jak do tej pory.

Jednak inne zachowania service worker sprawiają, że czujesz dezorientację. Zwłaszcza wtedy, gdy po odświeżeniu strony nie widzisz wprowadzonych zmian w kodzie.

Nowa warstwa

Zazwyczaj podczas tworzenia witryny musisz myśleć o 2 warstwach: klienta i serwera. Skrypt service worker to nowa warstwa, która znajduje się pośrodku.

Skrypt service worker pełni rolę pośredniej między klientem a serwerem.

Skrypt service worker to rodzaj rozszerzenia do przeglądarki, które Twoja witryna może zainstalować w przeglądarce użytkownika. Po zainstalowaniu mechanizm Service Worker extends przeglądarkę na potrzeby witryny za pomocą zaawansowanej warstwy środkowej. Ta warstwa skryptu service worker może przechwytywać i obsługiwać wszystkie żądania wysyłane przez Twoją witrynę.

Warstwa skryptu service worker ma swój własny cykl życia niezależny od karty przeglądarki. Samo odświeżenie strony nie wystarczy, aby zaktualizować skrypt service worker – tak samo jak nie oczekujesz odświeżenia strony w celu zaktualizowania kodu wdrożonego na serwerze. Każda warstwa ma własne, niepowtarzalne reguły aktualizowania.

W grze pracy usług omawiamy wiele szczegółów cyklu życia mechanizmów Service Worker i zapewniamy Ci mnóstwo ćwiczeń.

Wydajny, ale ograniczony

Wykorzystanie mechanizmów Service Worker w witrynie przynosi niesamowite korzyści. Twoja witryna może:

  • działają bezproblemowo nawet wtedy, gdy użytkownik jest offline
  • uzyskać ogromną poprawę wydajności dzięki pamięci podręcznej
  • korzystać z powiadomień push.
  • aplikacja musi być zainstalowana jako PWA,

Im więcej mogą zrobić pracownicy service worker, ale są one ograniczone z założenia. Nie mogą wykonywać żadnych czynności synchronicznych ani w tym samym wątku co Twoja witryna. Oznacza to brak dostępu do:

  • localStorage
  • DOM
  • okno

Dobra wiadomość jest taka, że istnieje kilka sposobów, w jakie Twoja strona może komunikować się ze skryptem service worker, w tym bezpośrednie postMessage, kanały wiadomości jeden do jednego oraz kanały radiowe (jeden do wielu).

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

Aktywny pracownik service worker utrzymuje się z konta nawet wtedy, gdy użytkownik opuści witrynę lub zamknie kartę. Przeglądarka przechowuje ten skrypt service worker, aby był gotowy, gdy użytkownik wróci do witryny. Przed wysłaniem pierwszego żądania skrypt service worker ma szansę je przechwycić i przejąć kontrolę nad stroną. To właśnie umożliwia witrynie pracę w trybie offline – skrypt service worker może udostępniać wersję strony z pamięci podręcznej, nawet jeśli użytkownik nie ma połączenia z internetem.

W pracach usługowych wizualizujemy tę koncepcję za pomocą Kolohe (sympatycznego skryptu service worker) przechwytującego i obsłużącego żądania.

Zatrzymano

Chociaż mechanizmy Service Worker wydają się nieśmiertelne, mogą zostać zatrzymane w każdej chwili. Przeglądarka nie chce marnować zasobów na skrypt service worker, który obecnie nic nie robi. Zatrzymanie nie jest tym samym co zamknięcie – skrypt service worker pozostaje zainstalowany i aktywowany. To jest właśnie uśpione. Gdy zajdzie następnym razem (np. w celu przetworzenia żądania), przeglądarka ponownie go aktywuje.

waitUntil

Skrypt service worker jest nieprzerwanie dostępny w trybie uśpienia, więc musi mieć możliwość sygnalizowania przeglądarki, że ma do czynienia z czymś ważnym, a nie ma ochoty ucinać sobie drzemki. W tym przypadku do akcji wkracza event.waitUntil(). Ta metoda wydłuża cykl życia, w którym jest używana, dzięki czemu nie zostaje zatrzymana i nie przechodzi do kolejnej fazy cyklu życia, dopóki nie będziemy gotowi. Daje nam to czas na skonfigurowanie pamięci podręcznych, pobranie zasobów z sieci itp.

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

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

Uważaj na stan globalny

W przypadku tego uruchomienia/zatrzymania globalny zakres skryptu service worker jest resetowany. Uważaj, aby w skrypcie service worker nie użyć żadnego stanu globalnego, ponieważ spowoduje to smutek, gdy ponownie się uruchomi i będzie mieć inny stan niż oczekiwano.

Przeanalizuj ten przykład, 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 rejestruje liczbę – powiedzmy: 0.13981866382421893. Zmienna hasHandledARequest zmieni się też na true. Skrypt service worker jest teraz przez pewien czas nieaktywny, więc przeglądarka go zatrzymuje. Następnym razem, gdy pojawi się żądanie, skrypt service worker jest potrzebny ponownie, więc przeglądarka go wybudza. Skrypt jest ponownie oceniany. Teraz hasHandledARequest został zresetowany do false, a favoriteNumber jest czymś zupełnie innym – 0.5907281835659033.

Nie możesz polegać na stanie przechowywanym w skrypcie service worker. Błędy mogą też powodować tworzenie wystąpień takich funkcji jak kanały wiadomości: za każdym razem, gdy skrypt service worker zatrzyma/uruchomi się, otrzymasz zupełnie nową instancję.

W rozdziale 3 systemów Service Worker wizualizujemy zatrzymane mechanizmy Service Worker, które w czasie oczekiwania na wybudzenie tracą wszystkie kolory.

wizualizacja zatrzymanego skryptu service worker

Razem, ale osobno

Stroną może sterować tylko jeden skrypt service worker naraz. Może jednak mieć zainstalowane jednocześnie 2 skrypty service worker. Gdy zmienisz kod skryptu service worker i odświeżysz stronę, w ogóle go nie edytujesz. Skrypty service worker są niezmienne. Zamiast tego tworzysz zupełnie nowy element. Ten nowy skrypt service worker (na przykład SW2) zostanie zainstalowany, ale jeszcze nie aktywuje. Musi poczekać na zakończenie działania obecnego skryptu service worker (SW1) (gdy użytkownik opuści witrynę).

Wykorzystywanie pamięci podręcznych innego skryptu service worker

Podczas instalacji SW2 może przeprowadzić konfigurację – zwykle tworzy i wypełnia pamięć podręczną. Pamiętaj jednak, że ten nowy skrypt service worker ma dostęp do wszystkiego, do czego ma dostęp obecny skrypt service worker. Jeśli nie zachowasz ostrożności, Twój nowy skrypt service worker może zepsuć problemy obecnemu skryptowi service worker. Oto kilka przykładów, które mogą spowodować problemy:

  • Oprogramowanie SW2 może usunąć pamięć podręczną, z której aktywnie korzysta ten program.
  • Komponent SW2 może zmodyfikować zawartość pamięci podręcznej używanej przez ten komponent, co spowoduje, że plik SW1 prześle w odpowiedzi zasoby, których strona się nie spodziewa.

Pomiń pominięcieOczekiwanie

Skrypt service worker może też użyć ryzykownej metody skipWaiting(), aby przejąć kontrolę nad stroną zaraz po zakończeniu instalacji. Zwykle jest to zły pomysł, chyba że celowo próbujesz zastąpić nieprawidłowy mechanizm Service Worker. Nowy skrypt service worker może używać zaktualizowanych zasobów, których nie oczekuje bieżąca strona, co prowadzi do błędów i błędów.

Rozpocznij czyszczenie

Sposobem na to, aby mechanizmy Service Worker się nie zamazały, jest używanie różnych pamięci podręcznych. Najłatwiej osiągnąć to, dodając wersje używanych 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 wdrażasz nowy skrypt service worker, kompresujesz skrypt version, aby spełniał wymagania i korzystał z całkowicie innej pamięci podręcznej niż poprzedni.

wizualizacja pamięci podręcznej

Zakończ sprzątanie

Gdy skrypt service worker osiągnie stan activated, oznacza to, że został przejęty i że poprzedni skrypt service worker jest nadmiarowy. Na tym etapie ważne jest wyczyszczenie po starym mechanizmie Service Worker. Nie tylko respektuje limity miejsca w pamięci podręcznej użytkowników, ale też zapobiega niezamierzonym błędom.

Metoda caches.match() jest często używanym skrótem do pobierania elementu z każdej pamięci podręcznej, w przypadku którego znaleziono dopasowanie. Jednak ta funkcja przechodzi przez pamięci podręczne 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. Na stronie jest oczekiwany nowszy skrypt, który jest przechowywany w lokalizacji assets-2. Jeśli jednak stara pamięć podręczna nie została usunięta, caches.match('app.js') zwróci starą pamięć z assets-1 i najprawdopodobniej nie będzie działać w Twojej witrynie.

Aby wyczyścić pamięć po poprzednich mechanizmach Service Worker, wystarczy usunąć pamięć podręczną, której nowy skrypt Service Worker 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);
          }
        });
      );
    });
  );
});

Zapobieganie zaśmiecaniu sobie nawzajem przez pracowników usługowych wymaga trochę pracy i dyscypliny, ale warto sobie z tym radzić.

Podejście skryptu service worker

Jeśli zaczniesz myśleć o pracownikach usługowych, zyskasz pewność siebie. Gdy je poznasz, zyskasz możliwość zapewniania swoim użytkownikom niezwykłych wrażeń.

Jeśli chcesz to zrozumieć, grając w grę, masz szczęście. Zagraj w Service Workies, aby poznać sposoby działania service worker, które pozwalają zabijać bestie offline.