Strategie dotyczące buforowania skryptu service worker

Do tej pory pojawiały się tylko wzmianki i małe fragmenty kodu interfejsu Cache. Aby efektywnie używać mechanizmów Service Worker, musisz zastosować co najmniej 1 strategię buforowania co wymaga znajomości interfejsu Cache.

Strategia buforowania to interakcja między zdarzeniem fetch skryptu service worker a interfejsem Cache. Sposób zapisywania strategii buforowania zależy od tego, na przykład lepiej obsługiwać żądania zasobów statycznych inaczej niż dokumenty, co wpływa na sposób tworzenia strategii buforowania.

Zanim przejdziemy do omówienia strategii, porozmawiajmy przez chwilę o tym, czym nie jest interfejs Cache, oraz krótkie podsumowanie niektórych dostępnych metod zarządzania pamięciami podręcznymi instancji service worker.

Interfejs Cache a pamięć podręczna HTTP

Jeśli nie znasz jeszcze interfejsu Cache, to może wydawać się kuszące, lub przynajmniej związane z pamięcią podręczną HTTP. To nieprawda.

  • Interfejs Cache jest mechanizmem buforowania całkowicie niezależnym od pamięci podręcznej HTTP.
  • Cokolwiek innego Cache-Control używana przez Ciebie do wpływu na pamięć podręczną HTTP nie ma wpływu na to, jakie zasoby są zapisywane w interfejsie Cache.

Pomyśl o pamięci podręcznej przeglądarki jako warstwowej. Pamięć podręczna HTTP to niskopoziomowa pamięć podręczna napędzana parami klucz-wartość z dyrektywami wyrażonymi w nagłówkach HTTP.

Interfejs Cache to natomiast pamięć podręczna wysokiego poziomu obsługiwana przez interfejs API JavaScript. Zapewnia to większą elastyczność niż w przypadku stosunkowo uproszczonych par klucz-wartość HTTP. co pozwala korzystać ze strategii buforowania. Oto kilka ważnych metod interfejsu API związanych z pamięciami podręcznymi skryptu service worker:

  • CacheStorage.open aby utworzyć nową instancję Cache.
  • Cache.add i Cache.put do przechowywania odpowiedzi sieci w pamięci podręcznej skryptu service worker.
  • Cache.match aby znaleźć odpowiedź z pamięci podręcznej w instancji Cache.
  • Cache.delete , aby usunąć odpowiedź z pamięci podręcznej z instancji Cache.

Oto niektóre spośród nich. Istnieją inne przydatne metody, ale to tylko podstawowe funkcje, które omówimy w dalszej części tego przewodnika.

Skromne wydarzenie fetch

Drugą połową strategii buforowania jest kod mechanizmu Service Worker fetch. Do tej pory w tej dokumentacji słyszeliśmy o „przechwytywaniu żądań sieciowych”, a w zdarzeniu fetch w skrypcie service worker

// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

self.addEventListener('install', (event) => {
  event.waitUntil(caches.open(cacheName));
});

self.addEventListener('fetch', async (event) => {
  // Is this a request for an image?
  if (event.request.destination === 'image') {
    // Open the cache
    event.respondWith(caches.open(cacheName).then((cache) => {
      // Respond with the image from the cache or from the network
      return cache.match(event.request).then((cachedResponse) => {
        return cachedResponse || fetch(event.request.url).then((fetchedResponse) => {
          // Add the network response to the cache for future visits.
          // Note: we need to make a copy of the response to save it in
          // the cache and use the original as the request response.
          cache.put(event.request, fetchedResponse.clone());

          // Return the network response
          return fetchedResponse;
        });
      });
    }));
  } else {
    return;
  }
});

To jest przykład zabawki – którym można przekonać się, jak działa to w praktyce. które pokazują, co potrafią specjaliści ds. usług. Powyższy kod wykonuje następujące operacje:

  1. Sprawdź właściwość destination żądania, by zobaczyć, czy to żądanie obrazu.
  2. Jeśli obraz znajduje się w pamięci podręcznej skryptu service worker, udostępniaj go stamtąd. Jeśli nie, pobierz obraz z sieci. zapisać odpowiedź w pamięci podręcznej i zwrócić odpowiedź sieciową.
  3. Wszystkie inne żądania są przekazywane przez mechanizm Service Worker bez interakcji z pamięcią podręczną.

Obiekt event pobierania zawiera element request usługa Znajdziesz tam informacje, które pomogą Ci zidentyfikować typ każdego żądania:

  • url czyli adres URL żądania sieciowego obsługiwanego obecnie przez zdarzenie fetch.
  • method która jest metodą żądania (np. GET lub POST).
  • mode z opisem trybu żądania. Wartość 'navigate' jest często używana do odróżniania żądań dokumentów HTML od innych żądań.
  • destination który opisuje typ żądanych treści w sposób umożliwiający uniknięcie użycia rozszerzenia pliku żądanego zasobu.

I teraz to asynchronizacja to nazwa gry. Na pewno pamiętasz, że zdarzenie install oferuje: event.waitUntil która przyjmuje obietnicę, i czeka na rozwiązanie problemu, zanim przejdziesz do aktywacji. Zdarzenie fetch ma podobne Metoda event.respondWith których można użyć do zwrócenia wyniku funkcji asynchronicznego fetch prośba lub odpowiedź zwrócona przez interfejs Cache match.

Strategie buforowania

Teraz już wiesz, jak działają instancje Cache i moduł obsługi zdarzeń fetch. czas na zapoznanie się ze strategiami buforowania skryptu service worker. Chociaż możliwości są praktycznie nieograniczone, bazują na strategiach dostarczanych z Workbox, dzięki czemu zorientować się, co dzieje się w wewnętrznej aplikacji Workbox.

Tylko pamięć podręczna

Pokazuje przepływ ze strony do skryptu service worker do pamięci podręcznej.

Zaczniemy od prostej strategii buforowania, którą będziemy nazywać „Tylko pamięć podręczna”. Chodzi o to, że gdy skrypt service worker kontroluje stronę, pasujące żądania będą zawsze trafiać do pamięci podręcznej. Oznacza to, że zasoby w pamięci podręcznej muszą być wstępnie zapisane w pamięci podręcznej, aby wzorzec mógł działać. i że zasoby te nie będą aktualizowane w pamięci podręcznej, dopóki skrypt service worker nie zostanie zaktualizowany.

// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

// Assets to precache
const precachedAssets = [
  '/possum1.jpg',
  '/possum2.jpg',
  '/possum3.jpg',
  '/possum4.jpg'
];

self.addEventListener('install', (event) => {
  // Precache assets on install
  event.waitUntil(caches.open(cacheName).then((cache) => {
    return cache.addAll(precachedAssets);
  }));
});

self.addEventListener('fetch', (event) => {
  // Is this one of our precached assets?
  const url = new URL(event.request.url);
  const isPrecachedRequest = precachedAssets.includes(url.pathname);

  if (isPrecachedRequest) {
    // Grab the precached asset from the cache
    event.respondWith(caches.open(cacheName).then((cache) => {
      return cache.match(event.request.url);
    }));
  } else {
    // Go to the network
    return;
  }
});

Powyżej tablica zasobów jest wstępnie buforowana podczas instalacji. Gdy skrypt service worker obsługuje pobieranie, sprawdzamy, czy adres URL żądania obsługiwany przez zdarzenie fetch znajduje się w tablicy zasobów wstępnie zapisanych w pamięci podręcznej. Jeśli tak jest, pobieramy zasób z pamięci podręcznej i pomijamy sieć. Pozostałe żądania przechodzą do sieci, i tylko w sieci. Aby zobaczyć, jak działa ta strategia, wypróbuj tę wersję demonstracyjną przy otwartej konsoli.

Tylko sieć

Pokazuje przepływ ze strony do skryptu service worker do sieci.

Przeciwieństwo opcji „Tylko pamięć podręczna” to „Tylko sieć”, gdy żądanie jest przekazywane przez skrypt service worker do sieci bez interakcji z pamięcią podręczną skryptu service worker. To dobry sposób na zapewnienie aktualności treści (np. za pomocą znaczników). ale w ogóle nie będzie działać, gdy użytkownik będzie offline.

Zapewnienie, że żądanie zostanie przekazane do sieci, wystarczy, że nie wywołasz usługi event.respondWith w odpowiedzi na pasujące żądanie. Jeśli chcesz wyrazić wulgarność, możesz użyć pustego pola return; w wywołaniu zwrotnym zdarzenia fetch dla żądań, które chcesz przekazać do sieci. To właśnie dzieje się w przypadku opcji „Tylko pamięć podręczna” prezentację strategii dla żądań, które nie są wstępnie w pamięci podręcznej.

Najpierw pamięć podręczna, a potem powrót do sieci

Pokazuje przepływ ze strony do skryptu service worker do pamięci podręcznej, a następnie do sieci, jeśli nie ma jej w pamięci podręcznej.

W tej strategii sprawy odgrywają nieco większą rolę. W przypadku żądań dopasowania proces wygląda tak:

  1. Żądanie trafia do pamięci podręcznej. Jeśli zasób jest w pamięci podręcznej, uruchom go z tego miejsca.
  2. Jeśli żądania nie ma w pamięci podręcznej, przejdź do sieci.
  3. Gdy żądanie sieciowe zostanie zakończone, dodaj je do pamięci podręcznej i zwraca odpowiedź z sieci.

Oto przykład tej strategii, który możesz przetestować prezentację na żywo:

// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

self.addEventListener('fetch', (event) => {
  // Check if this is a request for an image
  if (event.request.destination === 'image') {
    event.respondWith(caches.open(cacheName).then((cache) => {
      // Go to the cache first
      return cache.match(event.request.url).then((cachedResponse) => {
        // Return a cached response if we have one
        if (cachedResponse) {
          return cachedResponse;
        }

        // Otherwise, hit the network
        return fetch(event.request).then((fetchedResponse) => {
          // Add the network response to the cache for later visits
          cache.put(event.request, fetchedResponse.clone());

          // Return the network response
          return fetchedResponse;
        });
      });
    }));
  } else {
    return;
  }
});

Choć ten przykład dotyczy tylko obrazów, warto ją zastosować do wszystkich zasobów statycznych (np. CSS, JavaScript, obrazy i czcionki), zwłaszcza tych z postaciami oznaczonymi haszami. Zapewnia szybsze działanie zasobów niezmiennych, ponieważ pomija wszelkie próby sprawdzenia aktualności treści na serwerze, które mogą zostać uruchomione w pamięci podręcznej HTTP. Co ważniejsze, wszystkie zasoby z pamięci podręcznej będą dostępne offline.

Najpierw sieć, powrót do pamięci podręcznej

Pokazuje przepływ ze strony do skryptu service worker do sieci, a jeśli sieć jest niedostępna.

Jeśli zmienisz ustawienie „Najpierw pamięć podręczna, potem sieć” na głowie, pojawia się komunikat „Najpierw sieć, potem pamięć podręczna”. strategii. Jak to brzmi:

  1. Najpierw wysyłasz żądanie do sieci i umieszczasz odpowiedź w pamięci podręcznej.
  2. Jeśli później będziesz offline, powrócisz do najnowszej wersji tej odpowiedzi w pamięci podręcznej.

Ta strategia sprawdza się świetnie w przypadku żądań HTML i API, gdy gdy jesteś online, potrzebujesz najnowszej wersji zasobu, ale chcesz przyznać dostęp offline do najnowszej dostępnej wersji. Oto, jak to może wyglądać po zastosowaniu do żądań w kodzie HTML:

// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

self.addEventListener('fetch', (event) => {
  // Check if this is a navigation request
  if (event.request.mode === 'navigate') {
    // Open the cache
    event.respondWith(caches.open(cacheName).then((cache) => {
      // Go to the network first
      return fetch(event.request.url).then((fetchedResponse) => {
        cache.put(event.request, fetchedResponse.clone());

        return fetchedResponse;
      }).catch(() => {
        // If the network is unavailable, get
        return cache.match(event.request.url);
      });
    }));
  } else {
    return;
  }
});

Możesz to sprawdzić w wersji demonstracyjnej. Najpierw wejdź na daną stronę. Może być konieczne ponowne załadowanie, zanim odpowiedź HTML zostanie umieszczona w pamięci podręcznej. Następnie w narzędziach dla programistów symulację połączenia offline, i załaduj ponownie. Ostatnia dostępna wersja jest udostępniana natychmiast z pamięci podręcznej.

W sytuacjach, gdy praca w trybie offline jest ważna, ale trzeba zrównoważyć te możliwości z dostępem do najnowszych wersji znaczników lub danych API, „Najpierw sieć, potem pamięć podręczna” jest solidna strategia dążąca do osiągnięcia tego celu.

Nieaktualne – w trakcie ponownej weryfikacji

Pokazuje przepływ ze strony do skryptu service worker do pamięci podręcznej, a następnie z sieci do pamięci podręcznej.

Spośród omówionych do tej pory strategii „Nieużywanie w trakcie ponownej weryfikacji” jest najbardziej złożona. Jest ona pod pewnymi względami podobna do dwóch ostatnich strategii, ale procedura nadaje priorytet szybkości dostępu do zasobu, a jednocześnie aktualizować go w tle. Strategia ta wygląda mniej więcej tak:

  1. Przy pierwszym żądaniu zasobu pobierz go z sieci, umieścić go w pamięci podręcznej i zwrócić odpowiedź sieciową.
  2. Przy kolejnych żądaniach wyświetlaj zasób najpierw z pamięci podręcznej, a potem „w tle” Wyślij żądanie ponownie z sieci i zaktualizuj wpis w pamięci podręcznej zasobu.
  3. W przypadku kolejnych próśb otrzymasz ostatnią pobraną z sieci wersję, która została umieszczona w pamięci podręcznej w poprzednim kroku.

To doskonała strategia w przypadku informacji, które są dość ważne, aby były zawsze aktualne, ale nie mają znaczenia. Pomyśl o takich rzeczach jak awatary do witryn w mediach społecznościowych. Są aktualizowane, gdy użytkownicy z niej korzystają, Najnowsza wersja nie jest jednak wymagana przy każdym żądaniu.

// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

self.addEventListener('fetch', (event) => {
  if (event.request.destination === 'image') {
    event.respondWith(caches.open(cacheName).then((cache) => {
      return cache.match(event.request).then((cachedResponse) => {
        const fetchedResponse = fetch(event.request).then((networkResponse) => {
          cache.put(event.request, networkResponse.clone());

          return networkResponse;
        });

        return cachedResponse || fetchedResponse;
      });
    }));
  } else {
    return;
  }
});

Możesz zobaczyć, jak to działa w: kolejną prezentację na żywo, zwłaszcza na karcie Sieć w narzędziach dla programistów przeglądarki, i jego przeglądarki CacheStorage (o ile dostępne w przeglądarce narzędzia dla programistów ją zawierają).

Dalej do Workbox!

Ten dokument zawiera podsumowanie informacji o interfejsie API Service Worker, oraz powiązane interfejsy API, Oznacza to, że wiesz już wystarczająco dużo o tym, jak bezpośrednio używać mechanizmów Service Worker, aby zacząć eksperymentować z Workbox.