Buforowanie zasobów podczas działania

Niektóre komponenty w Twojej aplikacji internetowej mogą być używane rzadko lub bardzo duże albo różnić się w zależności od urządzenia użytkownika (np. obrazy elastyczne) lub języka. W takich przypadkach pamięci podręcznej może nie działać zgodnie z wzorcem – zamiast tego należy korzystać z pamięci podręcznej w czasie działania.

W Workbox możesz obsługiwać zapisywanie w pamięci podręcznej zasobów w czasie działania za pomocą modułu workbox-routing, aby dopasowywać trasy, oraz obsługiwać dla nich strategie buforowania za pomocą modułu workbox-strategies.

Strategie buforowania

Większość tras dla zasobów możesz obsłużyć za pomocą jednej z wbudowanych strategii buforowania. Zostały one szczegółowo omówione w tej dokumentacji, ale warto też przypomnieć sobie kilka z nich:

  • Nieaktywny podczas ponownej weryfikacji korzysta z odpowiedzi na żądanie z pamięci podręcznej, jeśli jest ona dostępna, i aktualizuje pamięć podręczną w tle o odpowiedź z sieci. Jeśli zasób nie jest przechowywany w pamięci podręcznej, będzie czekać na odpowiedź sieci i użyje go. Jest to dość bezpieczna strategia, ponieważ regularnie aktualizuje korzystające z niej wpisy w pamięci podręcznej. Wadą jest to, że zawsze wysyła w tle żądanie zasobu z sieci.
  • Sieć najpierw próbuje uzyskać odpowiedź z sieci. W przypadku otrzymania odpowiedzi przekazuje ona odpowiedź do przeglądarki i zapisuje ją w pamięci podręcznej. Jeśli żądanie sieciowe nie powiedzie się, zostanie użyta ostatnia odpowiedź z pamięci podręcznej. Umożliwi to dostęp offline do zasobu.
  • Cache First najpierw sprawdza pamięć podręczną pod kątem odpowiedzi i używa jej, jeśli jest dostępna. Jeśli żądania nie ma w pamięci podręcznej, jest używana sieć, a każda prawidłowa odpowiedź jest dodawana do pamięci podręcznej, zanim zostanie przesłana do przeglądarki.
  • Opcja Tylko sieć wymusza nadawanie odpowiedzi z sieci.
  • Ustawienie Tylko pamięć podręczna wymusza nadawanie odpowiedzi z pamięci podręcznej.

Możesz zastosować te strategie do wybranych żądań za pomocą metod oferowanych przez workbox-routing.

Stosowanie strategii buforowania z dopasowaniem tras

workbox-routing ujawnia metodę registerRoute, aby dopasowywać trasy i obsługuje je ze strategią buforowania. registerRoute akceptuje obiekt Route, który z kolei akceptuje 2 argumenty:

  1. Ciąg, wyrażenie regularne lub wywołanie zwrotne dopasowania określające kryteria dopasowania trasy.
  2. Moduł obsługi trasy – zwykle jest to strategia świadczona przez usługę workbox-strategies.

Dopasowywanie wywołań zwrotnych jest preferowane w przypadku dopasowywania tras, ponieważ zapewnia obiekt kontekstu zawierający obiekt Request, ciąg adresu URL żądania, zdarzenie pobierania oraz wartość logiczną, która określa, czy żądanie jest żądaniem z tej samej domeny.

Moduł obsługi obsługuje wówczas pasującą trasę. W poniższym przykładzie tworzona jest nowa trasa, która dopasowuje przychodzące żądania obrazu z tego samego pochodzenia i stosuje najpierw pamięć podręczną, a potem wybiera strategię sieciową.

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';

// A new route that matches same-origin image requests and handles
// them with the cache-first, falling back to network strategy:
const imageRoute = new Route(({ request, sameOrigin }) => {
  return sameOrigin && request.destination === 'image'
}, new CacheFirst());

// Register the new route
registerRoute(imageRoute);

Korzystanie z wielu pamięci podręcznych

Pole robocze umożliwia grupowanie odpowiedzi z pamięci podręcznej w oddzielnych instancjach Cache przy użyciu opcji cacheName, która jest dostępna w strategiach zbiorczych.

W poniższym przykładzie obrazy korzystają ze strategii nieaktualnej, podczas ponownej weryfikacji, a zasoby CSS i JavaScript używają strategii sieciowej z pamięci podręcznej. Trasa każdego zasobu powoduje umieszczenie odpowiedzi w osobnej pamięci podręcznej przez dodanie właściwości cacheName.

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst, StaleWhileRevalidate } from 'workbox-strategies';

// Handle images:
const imageRoute = new Route(({ request }) => {
  return request.destination === 'image'
}, new StaleWhileRevalidate({
  cacheName: 'images'
}));

// Handle scripts:
const scriptsRoute = new Route(({ request }) => {
  return request.destination === 'script';
}, new CacheFirst({
  cacheName: 'scripts'
}));

// Handle styles:
const stylesRoute = new Route(({ request }) => {
  return request.destination === 'style';
}, new CacheFirst({
  cacheName: 'styles'
}));

// Register routes
registerRoute(imageRoute);
registerRoute(scriptsRoute);
registerRoute(stylesRoute);
Zrzut ekranu z listą instancji pamięci podręcznej na karcie aplikacji w Narzędziach deweloperskich w Chrome. Wyświetlane są 3 różne pamięci podręczne: jedna o nazwie „skrypty”, druga o nazwie „styles”, a ostatnia o nazwie „images”.
Przeglądarka pamięci podręcznej w panelu Aplikacje w Narzędziach deweloperskich w Chrome. Odpowiedzi dla różnych typów zasobów są przechowywane w oddzielnych pamięciach podręcznych.

Ustawianie wygaśnięcia wpisów w pamięci podręcznej

Podczas zarządzania pamięciami podręcznymi skryptu service worker pamiętaj o limitach miejsca na dane. Usługa ExpirationPlugin upraszcza obsługę pamięci podręcznej i jest dostępna przez workbox-expiration. Aby go użyć, określ go w konfiguracji strategii buforowania:

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';

// Evict image cache entries older thirty days:
const imageRoute = new Route(({ request }) => {
  return request.destination === 'image';
}, new CacheFirst({
  cacheName: 'images',
  plugins: [
    new ExpirationPlugin({
      maxAgeSeconds: 60 * 60 * 24 * 30,
    })
  ]
}));

// Evict the least-used script cache entries when
// the cache has more than 50 entries:
const scriptsRoute = new Route(({ request }) => {
  return request.destination === 'script';
}, new CacheFirst({
  cacheName: 'scripts',
  plugins: [
    new ExpirationPlugin({
      maxEntries: 50,
    })
  ]
}));

// Register routes
registerRoute(imageRoute);
registerRoute(scriptsRoute);

Przestrzeganie limitów miejsca na dane może być skomplikowane. Warto wziąć pod uwagę użytkowników, którzy zmagają się z niewykorzystaniem miejsca na dane, lub którzy chcą maksymalnie wykorzystać swoją pamięć. Pary ExpirationPlugin w polu roboczym mogą pomóc w osiągnięciu tego celu.

Kwestie dotyczące różnych domen

Interakcja między skryptem service worker a zasobami z innych domen znacznie różni się od interakcji między zasobami tej samej domeny. Obsługa zasobów międzyźródłowych (CORS) jest skomplikowana, która obejmuje również sposób obsługi zasobów z różnych domen w skrypcie service worker.

Odpowiedzi nieprzezroczyste

Gdy wysyłasz żądanie z innej domeny w trybie no-cors, odpowiedź może być przechowywana w pamięci podręcznej skryptu service worker, a nawet może być wykorzystywana bezpośrednio w przeglądarce. Treść odpowiedzi nie można jednak odczytać za pomocą JavaScriptu. Jest to tzw. odpowiedź nieprzejrzysta.

Nieprzezroczyste odpowiedzi to zabezpieczenie, które uniemożliwia sprawdzenie zasobów z innych domen. Nadal możesz wysyłać żądania zasobów z innych domen, a nawet zapisywać je w pamięci podręcznej. Nie da się jednak odczytać treści odpowiedzi ani nawet odczytać jej kodu stanu.

Pamiętaj, aby włączyć tryb CORS

Nawet jeśli wczytujesz zasoby z innych domen, które mają ustawione mało rygorystyczne nagłówki CORS, które umożliwiają odczytywanie odpowiedzi, treść odpowiedzi z innych domen może być nieprzejrzysta. Na przykład poniższy kod HTML będzie wywoływać żądania no-cors, które będą prowadzić do niejednoznacznych odpowiedzi niezależnie od ustawionych nagłówków CORS:

<link rel="stylesheet" href="https://example.com/path/to/style.css">
<img src="https://example.com/path/to/image.png">

Aby wyraźnie aktywować żądanie cors, które zwraca nieprzezroczystą odpowiedź, musisz wyraźnie włączyć tryb CORS, dodając atrybut crossorigin do kodu HTML:

<link crossorigin="anonymous" rel="stylesheet" href="https://example.com/path/to/style.css">
<img crossorigin="anonymous" src="https://example.com/path/to/image.png">

Warto o tym pamiętać, gdy trasy w zasobach podrzędnych pamięci podręcznej skryptu service worker są wczytywane w czasie działania.

Skrzynka robocza nie może buforować nieprzezroczystych odpowiedzi

Domyślnie Workbox ostrożnie przechowuje w pamięci nieprzejrzyste odpowiedzi. Nie można zbadać kodu odpowiedzi pod kątem nieprzejrzystych odpowiedzi, więc przechowywanie odpowiedzi o błędzie w pamięci podręcznej może spowodować trwałe zakłócenie działania, jeśli stosowana jest strategia oparta na pamięci podręcznej lub tylko w pamięci podręcznej.

Jeśli chcesz przechowywać nieprzejrzystą odpowiedź w pamięci podręcznej w Workbox, użyj do jej obsługi strategii opartej na sieci lub nieaktualnej weryfikacji. Tak. Oznacza to, że żądania zasobu będą nadal wysyłane do sieci za każdym razem, ale dzięki temu nieudane odpowiedzi nie będą utrzymywały się i zostaną zastąpione prawidłowymi odpowiedziami.

Jeśli używasz innej strategii buforowania i zwrócona zostanie nieprzejrzysta odpowiedź, Workbox wyświetli ostrzeżenie, że odpowiedź nie została zapisana w pamięci podręcznej w trybie programowania.

Wymuszaj buforowanie nieprzezroczystych odpowiedzi

Jeśli absolutnie masz pewność, że chcesz buforować nieprzejrzystą odpowiedź, używając strategii opartej tylko na pamięci podręcznej lub tylko w pamięci podręcznej, możesz wymusić takie działanie za pomocą modułu workbox-cacheable-response:

import {Route, registerRoute} from 'workbox-routing';
import {NetworkFirst, StaleWhileRevalidate} from 'workbox-strategies';
import {CacheableResponsePlugin} from 'workbox-cacheable-response';

const cdnRoute = new Route(({url}) => {
  return url === 'https://cdn.google.com/example-script.min.js';
}, new CacheFirst({
  plugins: [
    new CacheableResponsePlugin({
      statuses: [0, 200]
    })
  ]
}))

registerRoute(cdnRoute);

Nieprzejrzyste odpowiedzi i interfejs API navigator.storage

Aby zapobiec wyciekowi informacji z wielu domen, do rozmiaru nieprzejrzystej odpowiedzi dodano znaczne dopełnienie do rozmiaru nieprzejrzystej odpowiedzi wykorzystywanej do obliczania limitów miejsca na dane. Ma to wpływ na sposób raportowania limitów miejsca przez interfejs API navigator.storage.

To dopełnienie różni się w zależności od przeglądarki, ale w przypadku Chrome minimalny rozmiar każdej nieprzejrzystej odpowiedzi z pamięci podręcznej wpływa na ogólne wykorzystanie miejsca na dane wynosi około 7 MB. Musisz mieć to na uwadze, określając, ile nieprzejrzystych odpowiedzi chcesz przechowywać w pamięci podręcznej, ponieważ limit miejsca na dane może łatwo zostać przekroczony znacznie szybciej, niż się spodziewasz.