Pracownicy serwisowi są potężni i absolutnie warci poznania. Pozwalają Ci dostarczyć użytkownikom zupełnie nowy poziom doświadczenia. Twoja strona może ładować się błyskawicznie. Może działać w trybie offline. Może być zainstalowana jako natywna aplikacja i czuć się tak samo dopracowana, ale z zasięgiem i swobodą sieci.

Ale pracownicy serwisu są niepodobni do niczego, do czego większość z nas, twórców stron internetowych, jest przyzwyczajona. Wiąże się z nimi stroma krzywa uczenia się i kilka błędów, na które trzeba uważać.

Google Developers i ja ostatnio współpracowaliśmy nad projektem – Service Workies – darmową grą pozwalającą zrozumieć pracowników usług. Budując ją i pracując nad skomplikowanymi tajnikami pracowników usługowych, natrafiłem na kilka przeszkód. Najbardziej pomogło mi wymyślenie kilku obrazowych metafor. W tym poście zbadamy te modele mentalne i owiniemy nasze mózgi wokół paradoksalnych cech, które sprawiają, że pracownicy usługowi są zarówno podstępni, jak i niesamowici.

Te same, ale inne #

Podczas kodowania pracownika usługowego wiele rzeczy będzie wydawało się znajomych. Używasz swoich ulubionych nowych funkcji języka JavaScript. Słuchasz zdarzeń cyklu życia tak samo jak w przypadku zdarzeń UI. Zarządzasz przepływem kontroli za pomocą obietnic, tak jak jesteś do tego przyzwyczajony.

Ale inne zachowania pracownika serwisu powodują, że drapiesz się po głowie w zakłopotaniu. Zwłaszcza gdy odświeżasz stronę i nie widzisz, że zmiany w kodzie zostały zastosowane.

Nowa warstwa #

Normalnie, gdy budujesz stronę, masz tylko dwie warstwy do przemyślenia: klienta i serwer. Pracownik serwisu jest zupełnie nową warstwą, która znajduje się pośrodku.

Myśl o swoim pracowniku serwisu jako o swego rodzaju rozszerzeniu przeglądarki – jednym, które twoja witryna może zainstalować w przeglądarce użytkownika. Po zainstalowaniu robotnik serwisowy rozszerza przeglądarkę o potężną warstwę pośrednią. Ta warstwa service worker może przechwytywać i obsługiwać wszystkie żądania Twojej witryny.

Warstwa service worker ma swój własny cykl życia, niezależny od karty przeglądarki. Proste odświeżenie strony nie wystarczy, aby zaktualizować pracownika usług – tak jak nie spodziewałbyś się, że odświeżenie strony zaktualizuje kod umieszczony na serwerze. Każda warstwa ma swoje własne, unikalne zasady aktualizacji.

W grze Service Workies omawiamy wiele szczegółów cyklu życia service worker i dajemy Ci mnóstwo praktyki w pracy z nim.

Myśl o swoim service worker jako o nowej warstwie pośredniej z własnym cyklem życia i metodami aktualizacji.

Potężny, ale ograniczony #

Mając service worker w swojej witrynie, zyskujesz niesamowite korzyści. Twoja witryna może:

  • działać bezbłędnie, nawet gdy użytkownik jest offline
  • uzyskać ogromne ulepszenia wydajności dzięki buforowaniu
  • używać powiadomień push
  • być zainstalowana jako PWA

Przy tak wielu rzeczach, jakie mogą zrobić pracownicy serwisu, są one ograniczone przez projekt. Nie mogą robić niczego synchronicznie lub w tym samym wątku co twoja strona. Oznacza to więc brak dostępu do:

  • localStorage
  • domu
  • okna

Dobrą wiadomością jest to, że istnieje kilka sposobów, na jakie twoja strona może komunikować się ze swoim pracownikiem obsługi, w tym bezpośrednie postMessage, kanały wiadomości jeden-do-jednego oraz kanały transmisji jeden-do-wielu.

Myśl o swoim pracowniku obsługi jako o czymś, co żyje poza twoją stroną. Możesz z nim rozmawiać, ale nie ma on bezpośredniego dostępu do twojej strony.

Długo żyjący, ale krótko żyjący #

Aktywny pracownik serwisu żyje nawet po opuszczeniu twojej strony przez użytkownika lub zamknięciu karty. Przeglądarka utrzymuje tego pracownika serwisu, aby był gotowy następnym razem, gdy użytkownik wróci na twoją stronę. Zanim zostanie wykonane pierwsze żądanie, robotnik serwisowy ma szansę przechwycić je i przejąć kontrolę nad stroną. To właśnie pozwala witrynie działać w trybie offline – robotnik serwisowy może obsługiwać zbuforowaną wersję samej strony, nawet jeśli użytkownik nie ma połączenia z Internetem.

W Service Workies wizualizujemy tę koncepcję za pomocą Kolohe (przyjaznego robotnika serwisowego) przechwytującego i obsługującego żądania.

Zatrzymany #

Pomimo tego, że robotnicy serwisowi wydają się być nieśmiertelni, mogą zostać zatrzymani niemal w każdej chwili. Przeglądarka nie chce marnować zasobów na pracownika serwisowego, który w danej chwili nic nie robi. Zatrzymanie nie jest tożsame z zakończeniem działania – robot usługowy pozostaje zainstalowany i aktywny. Jest on po prostu usypiany. Następnym razem, gdy będzie potrzebny (np. do obsługi żądania), przeglądarka obudzi go z powrotem.

waitUntil #

Z powodu ciągłej możliwości uśpienia, twój robot usługowy potrzebuje sposobu, aby dać przeglądarce znać, kiedy robi coś ważnego i nie ma ochoty na drzemkę. To właśnie tutaj event.waitUntil() wchodzi do gry. Metoda ta przedłuża cykl życia, w którym jest używana, powstrzymując ją zarówno przed zatrzymaniem, jak i przejściem do następnej fazy cyklu życia, dopóki nie będziemy gotowi. Daje nam to czas na utworzenie pamięci podręcznej, pobranie zasobów z sieci itp.

Ten przykład mówi przeglądarce, że nasz robot nie skończy się instalować, dopóki assets pamięć podręczna nie zostanie utworzona i wypełniona obrazkiem miecza:

self.addEventListener("install", event => {
event.waitUntil(
caches.open("assets").then(cache => {
return cache.addAll();
})
);
});

Uwaga na stan globalny #

Gdy to rozpoczęcie/zatrzymanie ma miejsce, globalny zakres robota serwisowego jest resetowany. Więc uważaj, aby nie używać żadnego stanu globalnego w swoim service worker lub będziesz smutny, gdy następnym razem obudzi się on z powrotem i będzie miał inny stan niż ten, którego oczekiwał.

Rozważmy 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;
});

Na każde żądanie ten service worker będzie rejestrował liczbę-powiedzmy 0.13981866382421893. Zmienna hasHandledARequest również zmienia się na true. Teraz robot usługowy siedzi bezczynnie przez jakiś czas, więc przeglądarka zatrzymuje go. Następnym razem, gdy pojawi się żądanie, pracownik serwisowy jest znowu potrzebny, więc przeglądarka go budzi. Jego skrypt jest ponownie analizowany. Teraz hasHandledARequest jest resetowane do false, a favoriteNumber jest czymś zupełnie innym –0.5907281835659033.

Nie można polegać na przechowywanym stanie w robotach serwisowych. Ponadto, tworzenie instancji rzeczy takich jak Message Channels może powodować błędy: otrzymasz zupełnie nową instancję za każdym razem, gdy pracownik serwisowy zatrzymuje się/uruchamia.

Ostrzeżenie: Ta pułapka jest szczególnie ważna, aby pamiętać o niej podczas pracy nad kodem pracownika serwisowego, ponieważ gdy Chrome DevTools jest otwarty, zachowanie start/stop jest wyłączone. Możesz nawet nie zauważyć błędów spowodowanych przez poleganie na stanie globalnym, dopóki nie zostaną one wysłane do użytkowników.

W rozdziale 3 Service Workies wizualizujemy naszego zatrzymanego service worker’a jako tracącego wszystkie kolory podczas oczekiwania na obudzenie.

Pomyśl o swoim service worker’ze jak o psie z whippetem. Jest szybki, lojalny i niesamowity. Będzie trzymał się przy tobie bez względu na wszystko. Ale przede wszystkim chce po prostu spać. Przez cały czas. Musisz dać mu znać, kiedy chcesz, żeby się nie obudził. Dobry piesek!

Razem, ale osobno #

Twoja strona może być kontrolowana tylko przez jednego pracownika serwisu naraz. Ale może mieć jednocześnie zainstalowanych dwóch robotników serwisowych. Kiedy dokonujesz zmiany w kodzie swojego pracownika serwisowego i odświeżasz stronę, w rzeczywistości wcale nie edytujesz swojego pracownika serwisowego. Service worker’y są niezmienne. Zamiast tego tworzysz zupełnie nowy. Ten nowy service worker (nazwijmy go SW2) zainstaluje się, ale nie będzie jeszcze aktywny. Musi poczekać, aż obecny pracownik serwisu (SW1) zakończy pracę (kiedy użytkownik opuści witrynę).

Mieszanie z pamięcią podręczną innego pracownika serwisu #

Podczas instalacji, SW2 może zająć się konfiguracją – zwykle tworzeniem i wypełnianiem pamięci podręcznej. Ale uwaga: ten nowy pracownik serwisu ma dostęp do wszystkiego, do czego ma dostęp obecny pracownik serwisu. Jeśli nie będziesz ostrożny, twój nowy oczekujący pracownik serwisu może naprawdę namieszać w pracy twojego aktualnego pracownika serwisu. Kilka przykładów, które mogą spowodować kłopoty:

  • SW2 może usunąć pamięć podręczną, z której aktywnie korzysta SW1.
  • SW2 może edytować zawartość pamięci podręcznej, z której korzysta SW1, powodując, że SW1 odpowiada zasobami, których strona nie oczekuje.

Skip skipWaiting #

Pracownik serwisu może również użyć ryzykownej metody skipWaiting(), aby przejąć kontrolę nad stroną, gdy tylko skończy instalację. Jest to generalnie zły pomysł, chyba że celowo próbujesz zastąpić błędnego pracownika serwisu. Nowy pracownik serwisu może używać zaktualizowanych zasobów, których bieżąca strona nie oczekuje, co prowadzi do błędów i usterek.

Start clean #

Sposobem na zapobieżenie wzajemnemu obijaniu się pracowników serwisu jest upewnienie się, że używają oni różnych pamięci podręcznych. Najłatwiejszym sposobem na osiągnięcie tego jest wersjonowanie nazw pamięci podręcznej, których używają.

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 nowego pracownika serwisu, podbijesz version, aby robił to, czego potrzebuje z całkowicie oddzielną pamięcią podręczną od poprzedniego pracownika serwisu.

End clean #

Gdy twój pracownik serwisu osiągnie stan activated, wiesz, że przejął kontrolę, a poprzedni pracownik serwisu jest zbędny (tj, nie jest już potrzebny). W tym momencie ważne jest, aby posprzątać po starym pracowniku serwisu. Nie tylko respektuje to limity pamięci podręcznej twoich użytkowników, ale może również zapobiec niezamierzonym błędom.

Metoda caches.match() jest często używanym skrótem do pobierania elementu z każdej pamięci podręcznej, w której jest dopasowanie. Ale iteruje ona przez pamięci podręczne w kolejności, w jakiej zostały one utworzone. Załóżmy więc, że masz dwie wersje pliku skryptu app.js w dwóch różnych pamięciach podręcznych – assets-1 i assets-2. Twoja strona oczekuje nowszego skryptu, który jest przechowywany w assets-2. Ale jeśli nie usunąłeś starego cache’u, caches.match('app.js') zwróci stary skrypt z assets-1 i najprawdopodobniej zepsuje twoją stronę.

Wszystko, czego potrzeba, aby posprzątać po poprzednich pracownikach serwisu, to usunięcie pamięci podręcznej, której nowy pracownik serwisu 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 temu, aby twoi pracownicy serwisu nie obijali się nawzajem, wymaga trochę pracy i dyscypliny, ale jest warte zachodu.

Pomyśl o połączeniu twojego pracownika serwisu i twojej witryny jako o aplikacji, którą można zainstalować. Każda wersja powinna działać. Każda wersja powinna być oddzielona od innych. Wyobraź sobie, jak zbugowana byłaby gra, gdyby deweloper przypadkowo wydał łatkę, która używała nowej logiki gry, ale przestarzałych aktywów. Wścieklibyście się na forach tak szybko! Utrzymuj swoje wersje aplikacji w porządku & clean.

Service worker mindset #

Getting into the right mindset while thinking about service workers will help you build yours with confidence. Kiedy już je opanujesz, będziesz w stanie tworzyć niesamowite doświadczenia dla swoich użytkowników.

Jeśli chcesz to wszystko zrozumieć, grając w grę, to masz szczęście! Idź zagrać w Service Workies, gdzie poznasz sposoby pracownika usług, aby zabić bestie offline.

Ostatnia aktualizacja: Jun 4, 2019 Popraw artykuł

.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.