Funkcje natychmiastowej nawigacji

Zastąpienie tradycyjnych technik pobierania z wyprzedzeniem mechanizmami service worker.

Wykonanie zadania w witrynie zwykle wymaga wykonania kilku czynności. Przykład: zakup produktu w witrynie e-commerce może obejmować wyszukanie produktu, wybranie go z listy wyników, dodanie go do koszyka i wykonanie operacji przez płacenie.

Z technicznego punktu widzenia poruszanie się po różnych stronach oznacza wysłanie żądania nawigacji. Zazwyczaj nie chcesz używać długotrwałych nagłówków Cache-Control do buforowania odpowiedzi HTML na potrzeby żądania nawigacji. Zwykle przesyła się je przez sieć z elementem Cache-Control: no-cache, by mieć pewność, że kod HTML oraz łańcuch kolejnych żądań sieciowych są (rozsądnie) aktualne. Jeśli użytkownik musi wejść na nową stronę, musi on z łatwością połączyć się z siecią przy każdym otwarciu nowej strony, co oznacza, że niestety każda nawigacja może działać wolno, a przynajmniej oznacza, że nie będzie działać niezawodnie.

Aby przyspieszyć przetwarzanie tych żądań, jeśli możesz przewidzieć działanie użytkownika, możesz wcześniej poprosić o dostęp do tych stron i zasobów i zachować je w pamięci podręcznej przez krótki czas, dopóki użytkownik nie kliknie tych linków. Ta technika nosi nazwę pobierania z wyprzedzeniem i jest powszechnie stosowana przez dodanie do stron tagów <link rel="prefetch">, które wskazują zasób do pobrania z wyprzedzeniem.

W tym przewodniku omówimy różne sposoby stosowania skryptów service worker jako uzupełnienie tradycyjnych technik pobierania z wyprzedzeniem.

Przypadki produkcyjne

MercadoLibre to największa witryna e-commerce w Ameryce Łacińskiej. Aby przyspieszyć nawigację, w niektórych częściach procesu wstawiane są dynamicznie tagi <link rel="prefetch">. Na przykład w przypadku stron z listą wyników pobierają następną stronę wyników, gdy tylko użytkownik przewinie stronę na sam dół:

Zrzut ekranu przedstawiający pierwszą i drugą stronę z informacjami o aplikacji w MercadoLibre oraz tag Link Prefetch łączący obie te strony.

Wczytywane z wyprzedzeniem pliki są żądane z „najniższym” priorytetem i przechowywane w pamięci podręcznej HTTP lub w pamięci podręcznej stanu strony internetowej (w zależności od tego, czy zasób jest buforowany) przez czas, który różni się w zależności od przeglądarki. Na przykład w Chrome 85 ta wartość wynosi 5 minut. Zasoby są przechowywane przez 5 minut. Po tym czasie obowiązują normalne reguły Cache-Control dotyczące tego zasobu.

Użycie pamięci podręcznej skryptu service worker może wydłużyć czas życia zasobów pobierania z wyprzedzeniem poza 5-minutowy okres.

Na przykład włoski portal sportowy Virgilio Sport używa pracowników usług do pobierania z wyprzedzeniem najpopularniejszych postów ze strony głównej. Korzystają też z interfejsu Network Information API, aby zapobiegać pobieraniu z wyprzedzeniem w przypadku użytkowników korzystających z połączenia 2G.

Logo Virgilio Sport.

W rezultacie w ciągu 3 tygodni obserwacji firma Virgilio Sport odnotowała czas wczytywania artykułów poprawiony o 78%, a liczba wyświetleń artykułów wzrosła o 45%.

Zrzut ekranu strony głównej i artykułów Virgilio Sport z danymi o wpływie po pobraniu z wyprzedzeniem.

Wdrażanie wstępnego buforowania za pomocą Workbox

W kolejnej sekcji wykorzystamy Workbox, aby pokazać, jak wdrożyć w mechanizmie Service Worker różne techniki buforowania, które można wykorzystać jako uzupełnienie <link rel="prefetch"> lub nawet zastępujące, całkowicie przekazując to zadanie skryptowi service worker.

1. Wstępnie buforuj strony statyczne i podrzędne strony

Dopuszczanie w pamięci podręcznej to możliwość zapisywania plików w pamięci podręcznej przez skrypt service worker podczas instalacji.

W tych przypadkach wstępne wczytywanie służy do osiągnięcia celu podobnego do wczytywania z wyprzedzeniem, czyli przyspieszenia nawigacji.

Blokowanie stron statycznych w pamięci podręcznej

W przypadku stron generowanych podczas kompilacji (np.about.html, contact.html) lub w całkowicie statycznych witrynach można po prostu dodać dokumenty witryny do listy z pamięci podręcznej. Dzięki temu będą one już dostępne w pamięci podręcznej za każdym razem, gdy użytkownik uzyska do nich dostęp:

workbox.precaching.precacheAndRoute([
  {url: '/about.html', revision: 'abcd1234'},
  // ... other entries ...
]);

Zasoby podrzędne strony wstępnego buforowania

Stosowanie w pamięci podręcznej zasobów statycznych, z których mogą korzystać różne sekcje witryny (np. JavaScript, CSS itp.), to ogólna sprawdzona metoda, która może dodatkowo zwiększyć skuteczność w przypadku scenariuszy pobierania z wyprzedzeniem.

Aby przyspieszyć nawigację w witrynie e-commerce, możesz użyć tagów <link rel="prefetch"> na stronach z informacjami o produktach, aby z wyprzedzeniem pobierać strony ze szczegółami produktów w przypadku kilku pierwszych produktów na stronie z informacjami. Jeśli masz już w pamięci podręcznej strony produktów, nawigacja może być jeszcze szybsza.

Aby to zrobić:

  • Dodaj do strony tag <link rel="prefetch">:
 <link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
  • Dodaj zasoby podrzędne stron do listy pamięci podręcznej w skrypcie service worker:
workbox.precaching.precacheAndRoute([
  '/styles/product-page.ac29.css',
  // ... other entries ...
]);

2. Wydłuż okres ważności zasobów pobierania z wyprzedzeniem

Jak już wspomnieliśmy, <link rel="prefetch"> pobiera zasoby i przechowuje je w pamięci podręcznej HTTP przez ograniczony czas. Po tym czasie obowiązują reguły Cache-Control dotyczące zasobu. Od wersji Chrome 85 ta wartość wynosi 5 minut.

Skrypty service worker pozwalają wydłużyć czas trwania stron pobierania z wyprzedzeniem, jednocześnie zapewniając dodatkowe korzyści w postaci udostępnienia tych zasobów do użytku w trybie offline.

W poprzednim przykładzie można uzupełnić atrybut <link rel="prefetch"> używany do wstępnego pobierania strony produktu za pomocą strategii buforowania środowiska wykonawczego w Workbox.

Aby to zrobić:

  • Dodaj do strony tag <link rel="prefetch">:
 <link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
  • W przypadku tych typów żądań zaimplementuj w skrypcie service worker strategię buforowania w czasie działania:
new workbox.strategies.StaleWhileRevalidate({
  cacheName: 'document-cache',
  plugins: [
    new workbox.expiration.Plugin({
      maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
    }),
  ],
});

W tym przypadku zdecydowaliśmy się użyć strategii „nieaktualny w trakcie ponownej weryfikacji”. W tej strategii żądania stron można wysyłać równolegle z pamięci podręcznej i z sieci. Odpowiedź pochodzi z pamięci podręcznej (jeśli jest dostępna) lub z sieci. Pamięć podręczna jest zawsze aktualizowana odpowiedzią sieciową po każdym pomyślnym żądaniu.

3. Przekazywanie wstępnego pobierania do skryptu service worker

W większości przypadków najlepszym rozwiązaniem jest użycie interfejsu <link rel="prefetch">. Tag jest wskazówką dotyczącą zasobów, która ma na celu jak najwydajniejsze pobieranie z wyprzedzeniem.

Jednak w niektórych przypadkach lepiej jest przekazać to zadanie w całości skryptowi service worker. Przykład: aby pobrać z wyprzedzeniem kilka pierwszych produktów ze strony z informacjami wyrenderowaną po stronie klienta, konieczne może być dynamiczne wstrzyknięcie na stronie kilku tagów <link rel="prefetch"> w zależności od odpowiedzi interfejsu API. Może to zużywać więcej czasu w głównym wątku strony i utrudniać implementację.

W takich przypadkach użyj „strategii komunikacji między skryptami stron a platformy Service Worker”, aby przekazać zadanie wczytywania z wyprzedzeniem do skryptu service worker. Komunikację tego typu można uzyskać za pomocą funkcji worker.postMessage():

Ikona strony łączącej dwukierunkową komunikację z skryptą service worker.

Pakiet okna okna roboczego upraszcza ten typ komunikacji, pochłaniając wiele szczegółów dotyczących wykonywanego wywołania.

Pobieranie z wyprzedzeniem w oknie skrzynki roboczej można zaimplementować w taki sposób:

  • Na stronie: wywołaj skrypt service worker, przekazując do niego typ komunikatu i listę adresów URL do pobrania z wyprzedzeniem:
const wb = new Workbox('/sw.js');
wb.register();

const prefetchResponse = await wb.messageSW({type: 'PREFETCH_URLS', urls: […]});
  • W skrypcie service worker: zaimplementuj moduł obsługi wiadomości, by wysyłać żądanie fetch() dla każdego adresu URL z wyprzedzeniem:
addEventListener('message', (event) => {
  if (event.data.type === 'PREFETCH_URLS') {
    // Fetch URLs and store them in the cache
  }
});