Przewodnik na temat imperatywnego buforowania

Andrew Guan
Andrew Guan

Niektóre strony mogą wymagać komunikacji z skryptem service worker bez konieczności poinformować o wyniku. Oto przykłady:

  • Strona wysyła do mechanizmu Service Worker listę adresów URL, do których pobierania z wyprzedzeniem. Dzięki temu, gdy użytkownik kliknie linki do zasobów podrzędnych dokumentu lub strony są już dostępne w pamięci podręcznej, dzięki czemu kolejne nawigacja działa znacznie szybciej.
  • Strona prosi skrypt service worker o pobranie i zapisanie w pamięci podręcznej zbioru najpopularniejszych artykułów, aby zostały do użytku w trybie offline.

Przekazywanie tego typu niekrytycznych zadań skryptowi service worker pozwala zwolnić w głównym wątku, aby ułatwić sobie wykonywanie pilniejszych zadań, takich jak odpowiadanie na interakcje użytkowników.

Schemat strony żądającej zasobów do zapisania w pamięci podręcznej przez skrypt service worker.

W tym przewodniku pokażemy, jak wdrożyć technikę jednokierunkowej komunikacji ze strony skrypt service worker za pomocą standardowych interfejsów API przeglądarki i biblioteki Workbox. Tego typu reklamy będziemy nazywać imperatywnym buforowaniu.

Sceneria produkcyjna

Firma 1-800-Flowers.com wdrożyła imperatywne buforowanie (wstępne pobieranie) z mechanizmami Service Worker za pomocą postMessage(), aby pobrać z wyprzedzeniem najpopularniejszych pozycji na stronach kategorii, aby przyspieszyć nawigację do stron ze szczegółami produktów.

Logo 1–800 kwiatów.

Stosują mieszane podejście, aby zdecydować, które elementy pobrać z wyprzedzeniem:

  • Podczas wczytywania strony prosi on skrypt servicer o pobranie danych JSON 9 pierwszych elementów. dodać wynikowe obiekty odpowiedzi do pamięci podręcznej.
  • Pozostałe elementy słuchają (mouseover) . W takim przypadku gdy użytkownik najedzie kursorem na element, może uruchomić pobieranie zasobu na żądanie.

Do przechowywania plików JSON używają interfejsu Cache API. odpowiedzi:

Logo 1–800 kwiatów.
Pobieranie z wyprzedzeniem danych produktów w formacie JSON ze stron z informacjami o produktach w 1-800Flowers.com.

Gdy użytkownik kliknie produkt, powiązane z nim dane JSON zostaną pobrane z pamięci podręcznej. bez konieczności łączenia się z siecią, co przyspiesza nawigację.

Korzystanie z Workbox

Workbox umożliwia łatwe wysyłanie wiadomości do skrypt service worker za pomocą pakietu workbox-window, czyli zestawu modułów które powinny działać w kontekście okna. Stanowią uzupełnienie innych pakietów Workbox. działające w skrypcie service worker.

Aby przekazać stronę z skryptem service worker, najpierw uzyskaj odniesienie do obiektu Workbox do zarejestrowany skrypt service worker:

const wb = new Workbox('/sw.js');
wb.register();

Następnie możesz wysłać wiadomość bezpośrednio deklaratywnie, bez konieczności pobierania rejestracji, sprawdzenia możliwości aktywacji lub myślenia o interfejsie API do komunikacji:

wb.messageSW({"type": "PREFETCH", "payload": {"urls": ["/data1.json", "data2.json"]}}); });

Skrypt service worker implementuje moduł obsługi message, aby nasłuchać tych wiadomości. Opcjonalnie może zwrócić odpowiedź, ale w takich przypadkach jest niewymagane:

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PREFETCH') {
    // do something
  }
});

Korzystanie z interfejsów API przeglądarki

Jeśli biblioteka Workbox nie wystarcza do Twoich potrzeb, możesz wdrożyć usługi typu window-to Service w ten sposób. komunikacji między pracownikami za pomocą interfejsów API w przeglądarkach.

Interfejs postMessage API mogą posłużyć do ustanowienia jednokierunkowego mechanizmu komunikacji między stroną a skrypcją service worker.

Strona wywołuje postMessage() interfejs skryptu service worker:

navigator.serviceWorker.controller.postMessage({
  type: 'MSG_ID',
  payload: 'some data to perform the task',
});

Skrypt service worker implementuje moduł obsługi message, aby nasłuchać tych wiadomości.

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === MSG_ID) {
    // do something
  }
});

Atrybut {type : 'MSG_ID'} nie jest absolutnie wymagany, ale jest to jeden ze sposobów zezwolenia strony na wysyłanie różnych typów instrukcji do skryptu service worker (np. „pobieranie z wyprzedzeniem” i „pobieranie z wyprzedzeniem” pamięci masowej”). Skrypt service worker może na podstawie tej flagi rozgałęziać się na różne ścieżki wykonania.

Jeśli operacja się uda, użytkownik będzie mógł czerpać z niej korzyści, ale w przeciwnym razie nie wpłynie to na główny proces użytkownika. Gdy na przykład 1-800-Flowers.com próbuje wstępnie buforować dane, strona nie musi wiedzieć, czy skrypt service worker się udał. Jeśli tak, użytkownicy będą mogli korzystać z szybszej nawigacji. Jeśli tak się nie stanie, musisz przejść na nową stronę. Potrwa to tylko trochę dłużej.

Prosty przykład pobierania z wyprzedzeniem

Jednym z najczęstszych zastosowań imperatywnego buforowania jest wstępne pobieranie, które polega na pobieraniu treści. zasobów dla danego adresu URL, zanim użytkownik przejdzie do niego, aby przyspieszyć nawigację.

W witrynach można wdrożyć pobieranie z wyprzedzeniem na różne sposoby:

W przypadku stosunkowo prostych scenariuszy pobierania z wyprzedzeniem, takich jak wstępne pobieranie dokumentów lub konkretne zasoby (JS, CSS itd.), te techniki są najlepsze.

Jeśli wymagane są dodatkowe mechanizmy logiczne, np. analiza zasobu pobierania z wyprzedzeniem (plik JSON lub strony) w pobierania wewnętrznych adresów URL, lepiej jest przekazać to zadanie w całości skrypt service worker.

Przekazywanie tego typu operacji do skryptu service worker ma następujące zalety:

  • Nie wymaga to ciężkiej pracy z pobieraniem i przetwarzaniem po pobieraniu (co zostanie wprowadzone później) do wątku dodatkowego. Dzięki temu wątek główny będzie obsługiwał ważniejsze takich jak reagowanie na interakcje użytkowników.
  • Umożliwienie wielu klientom (np. kart) korzystania ze wspólnej funkcji, a nawet wywoływaniu funkcji jednocześnie bez blokowania wątku głównego.

Wstępnie pobieraj strony ze szczegółami produktów

Pierwsze użycie postMessage() interfejsu mechanizmu Service Worker i przekazać tablicę adresów URL do pamięci podręcznej:

navigator.serviceWorker.controller.postMessage({
  type: 'PREFETCH',
  payload: {
    urls: [
      'www.exmaple.com/apis/data_1.json',
      'www.exmaple.com/apis/data_2.json',
    ],
  },
});

W skrypcie service worker zaimplementuj moduł obsługi message, aby przechwytuj i przetwarzaj wiadomości wysyłane przez dowolną aktywną kartę:

addEventListener('message', (event) => {
  let data = event.data;
  if (data && data.type === 'PREFETCH') {
    let urls = data.payload.urls;
    for (let i in urls) {
      fetchAsync(urls[i]);
    }
  }
});

W poprzednim kodzie wprowadziliśmy małą funkcję pomocniczą o nazwie fetchAsync(), która służy do iteracji tablicę adresów URL i wysyłać dla każdego z nich żądanie pobrania:

async function fetchAsync(url) {
  // await response of fetch call
  let prefetched = await fetch(url);
  // (optionally) cache resources in the service worker storage
}

Po uzyskaniu odpowiedzi możesz polegać na nagłówkach buforowania zasobu. W wielu przypadkach Tak jak na stronach ze szczegółami produktów, zasoby nie są przechowywane w pamięci podręcznej (co oznacza, że mają Cache-control nagłówek no-cache). W takich przypadkach możesz zmienić ten sposób działania, przez zapisując pobrany zasób w pamięci podręcznej mechanizmu Service Worker. Ma to też dodatkową zaletę: który ma być wyświetlany w sytuacjach offline.

Nie tylko dane JSON

Po pobraniu danych JSON z punktu końcowego serwera często zawierają one inne adresy URL, które również które warto pobrać z wyprzedzeniem, np. obrazu lub innych danych punktu końcowego, które są powiązane z danym pierwszym poziomem i skalowalnych danych.

Załóżmy, że w naszym przykładzie zwracane dane JSON to informacje o witrynie sklepu spożywczego:

{
  "productName": "banana",
  "productPic": "https://cdn.example.com/product_images/banana.jpeg",
  "unitPrice": "1.99"
 }

Zmodyfikuj kod fetchAsync(), aby iterować listę produktów i buforować baner powitalny dla każdy z nich:

async function fetchAsync(url, postProcess) {
  // await response of fetch call
  let prefetched = await fetch(url);

  //(optionally) cache resource in the service worker cache

  // carry out the post fetch process if supplied
  if (postProcess) {
    await postProcess(prefetched);
  }
}

async function postProcess(prefetched) {
  let productJson = await prefetched.json();
  if (productJson && productJson.product_pic) {
    fetchAsync(productJson.product_pic);
  }
}

W razie wystąpienia błędu 404 możesz też dodać obsługę wyjątków w tym kodzie. Urok stosowania skryptu service worker do pobierania z wyprzedzeniem polega na tym, że może się on w stosunku do treści na stronie i w wątku głównym. Możliwe też, że bardziej złożone logiki są bardziej elastyczne i oddzielne od danych. z obsługą klienta. Nie ma żadnych ograniczeń.

Podsumowanie

W tym artykule omówiliśmy typowy przypadek użycia jednokierunkowej komunikacji między stroną a usługą instancja robocza: imperatywne buforowanie. Omawiane przykłady mają zademonstrować tylko jeden sposób Wykorzystując ten wzorzec i to samo podejście, można je zastosować również do innych przypadków użycia, np. Zapisywanie najpopularniejszych artykułów na żądanie w pamięci podręcznej, aby można je było przeglądać offline, dodawać do zakładek itp.

Więcej wzorców komunikacji stron i mechanizmów Service Worker znajdziesz tutaj:

  • Aktualizacje komunikatów: wywołuje stronę z poziomu skryptu service worker w celu przekazania informacji o ważnych aktualizacjach (np. o nowej wersji aplikacji internetowej).
  • Komunikacja dwukierunkowa: przekazywanie zadania do skryptu service worker (np. pobieranie dużych ilości danych) oraz informowanie strony o postępach.