Życie pracowników service worker

Trudno jest określić, co robią specjaliści usług, bez zrozumienia ich cyklu życia. Ich wewnętrzne działanie może wydawać się nieprzejrzyste, a nawet dowolne. Warto pamiętać, że tak jak w przypadku każdego innego interfejsu API w przeglądarce zachowania mechanizmów Service Worker są dobrze zdefiniowane, i udostępniać aplikacje offline, a także ułatwić aktualizację bez zakłócania wrażeń użytkownika.

Przed rozpoczęciem korzystania z Workbox ważne jest zrozumienie cyklu życia skryptu service workbox, aby sprawdzić, co działa w Workbox.

Definiowanie terminów

Zanim przejdziemy do cyklu życia skryptu service worker, warto zdefiniować pewne terminy związane z tym cyklem życia.

Kontrola i zakres

Idea kontroli jest niezbędna do zrozumienia, jak działają mechanizmy Service Worker. Strona opisana jako kontrolowana przez skrypt service worker to strona, która umożliwia temu mechanizmowi przechwytywanie żądań sieciowych w jego imieniu. Skrypt service worker jest obecny i może wykonać pracę na stronie w danym zakresie.

Zakres

Zakres skryptu service worker zależy od jego lokalizacji na serwerze WWW. Jeśli skrypt service worker jest uruchomiony na stronie znajdującej się pod adresem /subdir/index.html i pod adresem /subdir/sw.js, zakres skryptu service worker to /subdir/. Aby zobaczyć, jak działa zakres, obejrzyj ten przykład:

  1. Nawiguj do https://service-worker-scope-viewer.glitch.me/subdir/index.html. Pojawi się komunikat informujący, że żaden skrypt service worker nie kontroluje strony. Jednak ta strona rejestruje skrypt service worker z https://service-worker-scope-viewer.glitch.me/subdir/sw.js.
  2. Odśwież stronę. Ponieważ skrypt service worker został zarejestrowany i jest teraz aktywny, kontroluje stronę. formularz zawierający zakres skryptu service worker, bieżący stan, a jej adres URL będzie widoczny. Uwaga: ponowne załadowanie strony nie ma nic wspólnego z zakresem, a nie cykl życia mechanizmów Service Worker, który omówimy później.
  3. Teraz otwórz stronę https://service-worker-scope-viewer.glitch.me/index.html. Mimo że skrypt service worker został zarejestrowany w tym źródle, nadal jest wyświetlany komunikat z informacją, że nie ma obecnie skryptu service worker. Dzieje się tak, ponieważ ta strona nie należy do zakresu zarejestrowanego skryptu service worker.

Zakres ogranicza strony, które są kontrolowane przez skrypt service worker. W tym przykładzie oznacza to, że skrypt service worker wczytany z /subdir/sw.js może kontrolować tylko strony znajdujące się w /subdir/ lub jego poddrzewie.

Powyżej pokazujemy, jak działa domyślne określanie zakresu. ale maksymalny dozwolony zakres można zastąpić, ustawiając nagłówek odpowiedzi Service-Worker-Allowed, oraz zdając scope do metody register.

Jeśli nie ma ważnego powodu, aby ograniczyć zakres skryptu service worker do podzbioru punktu początkowego, wczytuje skrypt service worker z katalogu głównego serwera WWW, aby jego zakres był jak najszerszy; i nie przejmuj się nagłówkiem Service-Worker-Allowed. Dla każdego jest to dużo prostsze.

Klient

Mówiąc w skrócie, że mechanizm Service Worker kontroluje stronę, tak naprawdę kontroluje klienta. Klient to dowolna otwarta strona, której adres URL wchodzi w zakres danego skryptu service worker. Chodzi konkretnie o WindowClient.

Cykl życia nowego skryptu service worker

Aby skrypt service worker mógł kontrolować stronę, najpierw trzeba go urzeczywistnić. Zacznijmy od tego, co się dzieje, gdy w witrynie bez aktywnego skryptu service worker zostanie wdrożony nowy skrypt service worker.

Rejestracja

Rejestracja jest początkowym etapem cyklu życia skryptu service worker:

<!-- In index.html, for example: -->
<script>
  // Don't register the service worker
  // until the page has fully loaded
  window.addEventListener('load', () => {
    // Is service worker available?
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/sw.js').then(() => {
        console.log('Service worker registered!');
      }).catch((error) => {
        console.warn('Error registering service worker:');
        console.warn(error);
      });
    }
  });
</script>

Ten kod działa w wątku głównym i wykonuje te czynności:

  1. Użytkownik po raz pierwszy odwiedza witrynę bez zarejestrowanego mechanizmu service worker, Poczekaj, aż strona zostanie w pełni wczytana, zanim ją zarejestrujesz. Pozwala to uniknąć rywalizacji o przepustowość, jeśli skrypt service worker dokonuje wstępnego buforowania.
  2. Chociaż mechanizm Service Worker ma dobre wsparcie, szybkie sprawdzenie pomaga uniknąć błędów w przeglądarkach, które nie są obsługiwane.
  3. Po całkowitym wczytaniu strony i – jeśli skrypt service worker jest obsługiwany, zarejestruj /sw.js.

Kwestie, o których należy pamiętać:

  • Skrypty service worker są tylko przez HTTPS lub localhost.
  • Jeśli zawartość skryptu service worker zawiera błędy składniowe, rejestracja nie powiedzie się, a skrypt service worker jest odrzucany.
  • Przypomnienie: mechanizmy Service Worker działają w zakresie. W tym przypadku zakresem jest całe źródło, ponieważ zostało wczytane z katalogu głównego.
  • Po rozpoczęciu rejestracji stan skryptu service worker zostanie ustawiony na 'installing'.

Instalacja rozpocznie się po zakończeniu rejestracji.

Instalacja

Skrypt service worker uruchamia install wydarzenie po rejestracji. Pole install jest wywoływane tylko raz na skrypt service worker i nie uruchomi się ponownie, dopóki nie zostanie zaktualizowane. Wywołanie zwrotne dla zdarzenia install można zarejestrować w zakresie instancji roboczej za pomocą addEventListener:

// /sw.js
self.addEventListener('install', (event) => {
  const cacheKey = 'MyFancyCacheName_v1';

  event.waitUntil(caches.open(cacheKey).then((cache) => {
    // Add all the assets in the array to the 'MyFancyCacheName_v1'
    // `Cache` instance for later use.
    return cache.addAll([
      '/css/global.bc7b80b7.css',
      '/css/home.fe5d0b23.css',
      '/js/home.d3cc4ba4.js',
      '/js/jquery.43ca4933.js'
    ]);
  }));
});

Spowoduje to utworzenie nowej instancji Cache i zapisanie zasobów w pamięci podręcznej. Będziemy później mieć dużo okazji, aby porozmawiać o wstępnym buforowaniu, skupmy się więc na roli event.waitUntil event.waitUntil akceptuje obietnicę, i czeka, aż ta obietnica zostanie spełniona. W tym przykładzie obietnica wykonuje 2 czynności asynchroniczne:

  1. Tworzy nową instancję Cache o nazwie 'MyFancyCache_v1'.
  2. Po utworzeniu pamięci podręcznej tablica adresów URL zasobów jest wstępnie buforowana przy użyciu Metoda addAll.

Instalacja się nie uda, jeśli obietnice przekazywane do event.waitUntilodrzucono. W takim przypadku skrypt service worker jest odrzucany.

Jeśli obietnica rozwiązuje, instalacja się powiedzie, stan skryptu service worker zmieni się na 'installed' i następnie zostanie aktywowany.

Aktywacja

Jeśli rejestracja i instalacja się powiedzie, skrypt service worker aktywuje się, a jego stan zmieni się na 'activating' Zadanie można wykonać podczas aktywacji w mechanizmie Service Worker activate zdarzenie. Typowym zadaniem w tym przypadku jest przycinanie starych pamięci podręcznych, ale w przypadku zupełnie nowego mechanizmu Service Worker, to w tej chwili nie jest aktualne, i zostanie rozwinięta, gdy będziemy omawiać aktualizacje skryptów service worker.

W przypadku nowych mechanizmów Service Worker activate uruchamia się natychmiast po pomyślnym zakończeniu install. Po zakończeniu aktywacji stan skryptu service worker zmieni się na 'activated'. Zwróć uwagę, że domyślnie nowy skrypt service worker nie zacznie kontrolować strony, dopóki nie nastąpi kolejna nawigacja lub odświeżenie strony.

Obsługa aktualizacji skryptu service worker

Po wdrożeniu pierwszego skryptu service worker trzeba będzie go później zaktualizować. Aktualizacja może być na przykład wymagana, jeśli wystąpią zmiany w obsłudze żądań lub wstępnym buforowaniu.

Kiedy mają miejsce aktualizacje

Przeglądarki sprawdzają dostępność aktualizacji skryptu service worker, gdy:

  • Użytkownik przechodzi na stronę w zakresie skryptu service worker.
  • navigator.serviceWorker.register() jest wywoływane z adresem URL innym niż obecnie zainstalowany mechanizm Service Worker – ale nie zmieniaj tego adresu.
  • navigator.serviceWorker.register() jest wywoływana z tym samym adresem URL co zainstalowany skrypt service worker, ale w innym zakresie. Aby tego uniknąć, w miarę możliwości umieść zakres w głównej części źródła.
  • Kiedy zdarzenia takie jak 'push' lub 'sync' zostały wywołane w ciągu ostatnich 24 godzin, ale nie musisz się jeszcze martwić o te zdarzenia.

Jak są aktualizacje

Warto wiedzieć, kiedy przeglądarka aktualizuje skrypt service worker, ale też „jak”. Zakładając, że URL lub zakres skryptu service worker nie ulegnie zmianie, obecnie zainstalowany mechanizm Service Worker jest aktualizowany do nowej wersji tylko wtedy, gdy jego zawartość uległa zmianie.

Przeglądarki wykrywają zmiany na kilka sposobów:

  • Wszelkie zmiany zachodzące w bajtach w skryptach żądanych przez importScripts (w odpowiednich przypadkach).
  • wszelkie zmiany w kodzie najwyższego poziomu skryptu service worker, co wpływa na odcisk cyfrowy wygenerowany przez przeglądarkę.

Przeglądarka wykonuje tu sporo zadań. Aby upewnić się, że przeglądarka ma wszystko, czego potrzebuje do niezawodności wykrywania zmian w treści skryptu service worker, nie każe przechowywać pamięci podręcznej HTTP ani zmieniać nazwy pliku. Przeglądarka automatycznie sprawdza dostępność aktualizacji, gdy następuje przejście na nową stronę w zakresie skryptu service worker.

Ręczne uruchamianie sprawdzania dostępności aktualizacji

W przypadku aktualizacji zasady rejestracji zwykle nie powinny ulec zmianie. Wyjątkiem może być sytuacja, w której sesje w witrynie są długotrwałe. Może to mieć miejsce w aplikacjach jednostronicowych, w których żądania nawigacji są rzadkie, ponieważ aplikacja zwykle napotyka 1 żądanie nawigacji na początku cyklu życia aplikacji. W takich sytuacjach w wątku głównym może zostać uruchomiona ręczna aktualizacja:

navigator.serviceWorker.ready.then((registration) => {
  registration.update();
});

W przypadku tradycyjnych witryn ani takich, które sesje użytkownika są długotrwałe, uruchamianie ręcznych aktualizacji prawdopodobnie nie jest konieczne.

Instalacja

Jeśli korzystasz z narzędzia do tworzenia pakietów i generujesz zasoby statyczne, te zasoby będą zawierać hasze w nazwie, na przykład framework.3defa9d2.js. Załóżmy, że niektóre z tych zasobów są wstępnie buforowane w celu późniejszego dostępu offline. Wymaga to aktualizacji skryptu service worker w celu wstępnego buforowania zaktualizowanych zasobów:

self.addEventListener('install', (event) => {
  const cacheKey = 'MyFancyCacheName_v2';

  event.waitUntil(caches.open(cacheKey).then((cache) => {
    // Add all the assets in the array to the 'MyFancyCacheName_v2'
    // `Cache` instance for later use.
    return cache.addAll([
      '/css/global.ced4aef2.css',
      '/css/home.cbe409ad.css',
      '/js/home.109defa4.js',
      '/js/jquery.38caf32d.js'
    ]);
  }));
});

Dwie rzeczy różnią się od pierwszego przykładowego zdarzenia install:

  1. Zostanie utworzona nowa instancja Cache z kluczem 'MyFancyCacheName_v2'.
  2. Nazwy zasobów w pamięci podręcznej uległy zmianie.
.

Warto zauważyć, że zaktualizowany skrypt service worker jest instalowany razem z poprzednim. Oznacza to, że stary mechanizm Service Worker nadal ma kontrolę nad wszystkimi otwartymi stronami i po instalacji, nowy kod przechodzi w stan oczekiwania, aż zostanie aktywowany.

Domyślnie nowy skrypt service worker aktywuje się, gdy stary skrypt nie kontroluje żadnych klientów. Dzieje się tak, gdy wszystkie otwarte karty danej witryny są zamknięte.

Aktywacja

Po zainstalowaniu zaktualizowanego skryptu service worker i zakończeniu fazy oczekiwania zostanie aktywowany, a stary skrypt service worker jest odrzucany. Typowym zadaniem w przypadku zaktualizowanego zdarzenia activate skryptu service worker jest usunięcie starych pamięci podręcznych. Usuń stare pamięci podręczne, pobierając klucze dla wszystkich otwartych instancji Cache za pomocą caches.keys. i usuwania pamięci podręcznych, których nie ma na zdefiniowanej liście dozwolonych, caches.delete:

self.addEventListener('activate', (event) => {
  // Specify allowed cache keys
  const cacheAllowList = ['MyFancyCacheName_v2'];

  // Get all the currently active `Cache` instances.
  event.waitUntil(caches.keys().then((keys) => {
    // Delete all caches that aren't in the allow list:
    return Promise.all(keys.map((key) => {
      if (!cacheAllowList.includes(key)) {
        return caches.delete(key);
      }
    }));
  }));
});

Stare pamięci podręczne nie są usuwane. Musimy to zrobić sami, bo w przeciwnym razie istnieje ryzyko, limity miejsca na dane. Skrypt 'MyFancyCacheName_v1' z pierwszego skryptu service worker jest nieaktualny, lista dozwolonych buforowania jest aktualizowana, aby określić 'MyFancyCacheName_v2', które usuwa pamięci podręczne o innej nazwie.

Zdarzenie activate zakończy się po usunięciu starej pamięci podręcznej. W tym momencie nowy skrypt service worker przejmie kontrolę nad stroną, w końcu zastąpię stary!

Cykl życia trwa bez końca

Określa, czy aplikacja Workbox jest używana do obsługi wdrażania i aktualizacji skryptu service worker lub interfejsu Service Worker API użyto bezpośrednio, Warto znać cykl życia skryptów service worker. Z tego powodu zachowania mechanizmów Service Worker powinny wydawać się bardziej logiczne niż tajemnicze.

Jeśli chcesz dowiedzieć się więcej, warto sprawdzić tym artykułem Jake'a Archibalda. Cały cykl życia usług jest zróżnicowany, ale stają się też znane, a korzystanie z Workboxów przyniesie wiele korzyści.