Aktywna

Kluczową cechą progresywnych aplikacji internetowych jest to, że są niezawodne, szybko ładują zasoby, utrzymują zaangażowanie użytkowników i niezwłocznie przekazują informacje zwrotne, nawet w słabych warunkach sieciowych. Jak to możliwe? Dzięki zdarzeniu fetch skryptu service worker.

Zdarzenie pobierania

Obsługa przeglądarek

  • 40
  • 17
  • 44
  • 11.1

Źródło

Zdarzenie fetch pozwala nam przechwytywać wszystkie żądania sieciowe wysyłane przez PWA w zakresie skryptu service worker zarówno w przypadku żądań z tej samej domeny, jak i z innych domen. Oprócz obsługi elementów nawigacyjnych i żądań zasobów pobieranie z zainstalowanego mechanizmu Service Worker pozwala na renderowanie wizyt na stronach po pierwszym wczytaniu witryny bez wywołań sieciowych.

Moduł obsługi fetch otrzymuje wszystkie żądania z aplikacji, w tym adresy URL i nagłówki HTTP, i pozwala deweloperowi aplikacji zdecydować, jak je przetworzyć.

Skrypt service worker znajduje się między klientem a siecią.

Skrypt service worker może przekierować żądanie do sieci, udzielić odpowiedzi z pamięci podręcznej lub utworzyć nową. Wybór należy do Ciebie. Oto prosty przykład:

self.addEventListener("fetch", event => {
    console.log(`URL requested: ${event.request.url}`);
});

Odpowiadanie na żądanie

Masz dwie rzeczy, które możesz zrobić, gdy żądanie dociera do skryptu service worker: możesz je zignorować, a następnie przesłać do sieci, lub odpowiedzieć na nie. Odpowiadanie na żądania z poziomu skryptu service worker pozwala wybrać, co i w jaki sposób ma być zwracane do PWA, nawet jeśli użytkownik jest offline.

Aby odpowiedzieć na żądanie przychodzące, wywołaj event.respondWith() z modułu obsługi zdarzeń fetch w ten sposób:

// fetch event handler in your service worker file
self.addEventListener("fetch", event => {
    const response = .... // a response or a Promise of response
    event.respondWith(response);
});

Musisz wywołać respondWith() synchronicznie i musisz zwrócić obiekt Response. Nie możesz jednak wywołać respondWith() po zakończeniu obsługi zdarzenia pobierania, na przykład w wywołaniu asynchronicznym. Jeśli musisz poczekać na pełną odpowiedź, możesz przekazać do usługi respondWith() obietnicę, która zakończy się odpowiedzią.

Tworzenie odpowiedzi

Interfejs Fetch API umożliwia tworzenie odpowiedzi HTTP w kodzie JavaScript. Mogą one być zapisywane w pamięci podręcznej za pomocą interfejsu Cache Storage API i zwracane tak, jakby pochodziły z serwera WWW.

Aby utworzyć odpowiedź, utwórz nowy obiekt Response, ustawiając jego treść i opcje, takie jak stan i nagłówki:

const simpleResponse = new Response("Body of the HTTP response");

const options = {
   status: 200,
   headers: {
    'Content-type': 'text/html'
   }
};
const htmlResponse = new Response("<b>HTML</b> content", options)

Odpowiadanie z pamięci podręcznej

Wiesz już, jak obsługiwać odpowiedzi HTTP z skryptu service worker, więc pora użyć interfejsu pamięci podręcznej, by przechowywać zasoby na urządzeniu.

Możesz użyć interfejsu Cache Storage API, aby sprawdzić, czy żądanie otrzymane z PWA jest dostępne w pamięci podręcznej, a jeśli tak, wyślij tym żądaniem do respondWith(). W tym celu musisz najpierw przeszukać pamięć podręczną. Funkcja match(), dostępna w interfejsie caches najwyższego poziomu, przeszukuje wszystkie magazyny w źródle lub jeden otwarty obiekt pamięci podręcznej.

Funkcja match() odbiera żądanie HTTP lub adres URL jako argument i zwraca obietnicę, która kończy się odpowiedzią powiązaną z odpowiednim kluczem.

// Global search on all caches in the current origin
caches.match(urlOrRequest).then(response => {
   console.log(response ? response : "It's not in the cache");
});

// Cache-specific search
caches.open("pwa-assets").then(cache => {
  cache.match(urlOrRequest).then(response => {
    console.log(response ? response : "It's not in the cache");
  });
});

Strategie buforowania

Wyświetlanie plików tylko z pamięci podręcznej przeglądarki nie pasuje do każdego przypadku użycia. Na przykład użytkownik lub przeglądarka może wyczyścić pamięć podręczną. Dlatego musisz zdefiniować własne strategie przesyłania zasobów PWA. Nie musisz ograniczać się do jednej strategii buforowania. Możesz zdefiniować różne wzorce dla różnych wzorców adresów URL. Możesz na przykład mieć jedną strategię dotyczącą minimalnej liczby zasobów interfejsu, drugą dla wywołań interfejsu API i trzecią dla adresów URL obrazów i danych. Aby to zrobić, przeczytaj event.request.url w ServiceWorkerGlobalScope.onfetch i przeanalizuj ją za pomocą wyrażeń regularnych lub wzorca adresu URL. (Obecnie wzorzec adresu URL nie jest obsługiwany na niektórych platformach).

Oto najczęstsze strategie:

Najpierw pamięć podręczna
Najpierw wyszukuje odpowiedź z pamięci podręcznej, a gdy jej nie znajdzie, wraca do sieci.
Najpierw sieć
Najpierw wysyła żądanie odpowiedzi od sieci, a jeśli żadna nie jest zwracana, sprawdza odpowiedź w pamięci podręcznej.
Nieaktualny podczas ponownej weryfikacji
Wyświetla odpowiedź z pamięci podręcznej, podczas gdy w tle wysyła żądanie najnowszej wersji i zapisuje ją w pamięci podręcznej na następne żądanie zasobu.
Tylko sieć
Zawsze odpowiada z siecią lub komunikatem o błędach. Nigdy nie korzystamy z pamięci podręcznej.
Tylko pamięć podręczna
Zawsze odpowiada z pamięci podręcznej lub komunikatami o błędach. Sieć nigdy nie będzie konsultowana. Zasoby, które będą wyświetlane z użyciem tej strategii, muszą zostać dodane do pamięci podręcznej, zanim zostaną wysłane.

Najpierw z pamięci podręcznej

Przy użyciu tej strategii skrypt service worker wyszukuje pasujące żądanie w pamięci podręcznej i zwraca odpowiednią odpowiedź, jeśli jest zapisana w pamięci podręcznej. W przeciwnym razie pobiera odpowiedź z sieci (opcjonalnie aktualizując pamięć podręczną na potrzeby przyszłych wywołań). Jeśli nie ma odpowiedzi z pamięci podręcznej, ani odpowiedzi sieci, żądanie spowoduje błąd. Wyświetlanie komponentów bez połączenia z siecią zwykle trwa krócej, dlatego ta strategia traktuje priorytetowo skuteczność, a nie aktualność.

Strategia Cache First

self.addEventListener("fetch", event => {
   event.respondWith(
     caches.match(event.request)
     .then(cachedResponse => {
       // It can update the cache to serve updated content on the next request
         return cachedResponse || fetch(event.request);
     }
   )
  )
});

Najpierw sieć

Strategia ta jest kopią strategii Cache First. Sprawdza, czy żądanie może zostać zrealizowane z sieci, a jeśli to niemożliwe, próbuje pobrać żądanie z pamięci podręcznej. Najpierw zadbaj o pamięć podręczną. Jeśli nie ma odpowiedzi sieciowej ani pamięci podręcznej, żądanie spowoduje błąd. Uzyskanie odpowiedzi z sieci zwykle trwa dłużej niż jej uzyskanie z pamięci podręcznej. Ta strategia traktuje priorytetowo zaktualizowane treści, a nie wydajność.

Strategia „Network First”

self.addEventListener("fetch", event => {
   event.respondWith(
     fetch(event.request)
     .catch(error => {
       return caches.match(event.request) ;
     })
   );
});

Nieaktualny podczas ponownej weryfikacji

Nieaktualna strategia ponownej weryfikacji zwraca natychmiastową odpowiedź z pamięci podręcznej, a następnie sprawdza sieć pod kątem aktualizacji i zastępuje odpowiedź zapisaną w pamięci podręcznej, jeśli zostanie ona znaleziona. Ta strategia zawsze wysyła żądanie sieciowe, ponieważ nawet jeśli znajdzie się zasób przechowywany w pamięci podręcznej, będzie próbowała zaktualizować zawartość pamięci podręcznej o dane otrzymane z sieci, by w następnym żądaniu użyć zaktualizowanej wersji. Dzięki tej strategii można korzystać z szybkiego udostępniania kodu w pierwszej kolejności i aktualizować pamięć podręczną w tle.

Nieaktualny podczas ponownej weryfikacji strategii

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cachedResponse => {
        const networkFetch = fetch(event.request).then(response => {
          // update the cache with a clone of the network response
          const responseClone = response.clone()
          caches.open(url.searchParams.get('name')).then(cache => {
            cache.put(event.request, responseClone)
          })
          return response
        }).catch(function (reason) {
          console.error('ServiceWorker fetch failed: ', reason)
        })
        // prioritize cached response over network
        return cachedResponse || networkFetch
      }
    )
  )
})

Tylko sieć

Strategia dotycząca tylko sieci jest podobna do sposobu działania przeglądarek bez skryptu service worker lub interfejsu Cache Storage API. Żądanie zwraca zasób tylko wtedy, gdy można go pobrać z sieci. Jest to często przydatne w przypadku zasobów takich jak żądania do interfejsu API dostępne tylko online.

Strategia „Tylko sieć”

Tylko pamięć podręczna

Strategia dotycząca tylko pamięci podręcznej zapewnia, że żądania nigdy nie trafiają do sieci. Na wszystkie żądania przychodzące są wysyłane wstępnie wypełnione elementy pamięci podręcznej. Ten kod używa modułu obsługi zdarzeń fetch z metodą match pamięci podręcznej tylko do odpowiadania na pamięć podręczną:

self.addEventListener("fetch", event => {
   event.respondWith(caches.match(event.request));
});

Strategia dotycząca tylko pamięci podręcznej.

Strategie niestandardowe

Chociaż opisane powyżej są typowe strategie buforowania, to Ty odpowiadasz za skrypt service worker i sposób obsługi żądań. Jeśli żaden z nich nie odpowiada Twoim potrzebom, możesz stworzyć własny.

Możesz np. użyć strategii opartej na pierwszej sieci z ustawionym limitem czasu oczekiwania, aby nadać priorytet aktualizowanym treściom, ale tylko wtedy, gdy odpowiedź wyświetli się w ustawionym przez Ciebie progu. Możesz też scalić odpowiedź z pamięci podręcznej z odpowiedzią sieciową i utworzyć złożoną odpowiedź z poziomu skryptu service worker.

Aktualizuję zasoby

Aktualizowanie zasobów PWA w pamięci podręcznej może stanowić wyzwanie. Nieaktualna w trakcie ponownej weryfikacji strategii to jedno, ale nie jedyny sposób. W rozdziale o aktualizacji poznasz różne techniki aktualizowania treści i zasobów aplikacji.

Zasoby