Obsługa żądań

Kluczowym aspektem progresywnych aplikacji internetowych jest ich niezawodność. Mogą one szybko wczytywać zasoby, dzięki czemu użytkownicy są zaangażowani i od razu otrzymują informacje zwrotne, nawet w przypadku słabego połączenia z siecią. Jak to możliwe? Dzięki zdarzeniu fetch service worker.

Zdarzenie pobierania

Browser Support

  • Chrome: 40.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 11.1.

Source

Zdarzenie fetch umożliwia nam przechwytywanie każdego żądania sieciowego wysyłanego przez PWA w zakresie robota usługi, zarówno w przypadku żądań dotyczących tego samego pochodzenia, jak i żądań dotyczących różnych pochodzeń. Oprócz żądań nawigacji i zasobów pobieranie danych z zainstalowanego service workera umożliwia renderowanie stron po pierwszym załadowaniu witryny bez wywoływania sieci.

Procedura obsługi fetch otrzymuje wszystkie żądania z aplikacji, w tym adresy URL i nagłówki HTTP, i pozwala deweloperowi aplikacji decydować o sposobie ich przetwarzania.

Service worker znajduje się między klientem a siecią.

Skrypt service worker może przekazać żądanie do sieci, odpowiedzieć wcześniej zapisaną w pamięci podręcznej odpowiedzią lub utworzyć nową odpowiedź. Wybór należy do Ciebie. Oto prosty przykład:

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

Odpowiadanie na prośbę

Gdy do skryptu service worker dociera żądanie, możesz je zignorować (wtedy zostanie ono przekazane do sieci) lub na nie odpowiedzieć. Odpowiadanie na żądania z poziomu skryptu service worker umożliwia wybieranie, co i w jaki sposób ma być zwracane do Twojej progresywnej aplikacji internetowej, nawet gdy użytkownik jest offline.

Aby odpowiedzieć na przychodzące żądanie, wywołaj funkcję event.respondWith() w ramach procedury obsługi zdarzeń fetch, na przykład tak:

// 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ć funkcję respondWith() synchronicznie i zwrócić obiekt Response. Nie możesz jednak wywołać respondWith() po zakończeniu działania procedury obsługi zdarzenia pobierania, np. w wywołaniu asynchronicznym. Jeśli musisz poczekać na pełną odpowiedź, możesz przekazać do funkcji respondWith() obiekt Promise, który zostanie rozwiązany z odpowiedzią.

Tworzenie odpowiedzi

Dzięki interfejsowi Fetch API możesz tworzyć odpowiedzi HTTP w kodzie JavaScript. Odpowiedzi te można zapisywać w pamięci podręcznej za pomocą interfejsu Cache Storage API i zwracać tak, jakby pochodziły z serwera internetowego.

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 wyświetlać odpowiedzi HTTP z usługi Service Worker. Teraz możesz użyć interfejsu Caching Storage, aby przechowywać komponenty na urządzeniu.

Za pomocą interfejsu Cache Storage API możesz sprawdzić, czy żądanie otrzymane z PWA jest dostępne w pamięci podręcznej, a jeśli tak, odpowiedzieć na respondWith(). Aby to zrobić, musisz najpierw wyszukać informacje w pamięci podręcznej. Funkcja match(), dostępna w interfejsie najwyższego poziomu caches, przeszukuje wszystkie sklepy w Twoim źródle lub w jednym otwartym obiekcie pamięci podręcznej.

Funkcja match() przyjmuje jako argument żądanie HTTP lub adres URL i zwraca obietnicę, która jest rozwiązywana za pomocą odpowiedzi powiązanej 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 sprawdza się w każdym przypadku. Na przykład użytkownik lub przeglądarka mogą usunąć dane z pamięci podręcznej. Dlatego warto zdefiniować własne strategie dostarczania komponentów do progresywnej aplikacji internetowej. Nie musisz ograniczać się do jednej strategii buforowania. Możesz zdefiniować różne wzorce dla różnych wzorców URL. Możesz na przykład mieć jedną strategię dla minimalnych zasobów interfejsu, drugą dla wywołań interfejsu API, a trzecią dla adresów URL obrazów i danych. Aby to zrobić, przeczytaj event.request.urlServiceWorkerGlobalScope.onfetch i przeanalizuj je za pomocą wyrażeń regularnych lub wzoru adresu URL. (W momencie pisania tego artykułu wzorzec adresu URL nie jest obsługiwany na wszystkich platformach).

Najczęstsze strategie to:

Najpierw pamięć podręczna
Najpierw wyszukuje odpowiedź w pamięci podręcznej, a jeśli jej nie znajdzie, korzysta z sieci.
Najpierw sieć
Najpierw wysyła żądanie odpowiedzi z sieci, a jeśli nie zostanie ona zwrócona, sprawdza, czy odpowiedź znajduje się w pamięci podręcznej.
Stale While Revalidate
Odpowiada z pamięci podręcznej, a w tle wysyła żądanie najnowszej wersji i zapisuje ją w pamięci podręcznej na wypadek, gdyby zasób był potrzebny w przyszłości.
Tylko sieć
Zawsze odpowiada odpowiedzią z sieci lub zwraca błąd. Pamięć podręczna nigdy nie jest sprawdzana.
Tylko pamięć podręczna
Zawsze odpowiada, korzystając z pamięci podręcznej, lub zwraca błąd. Sieć nigdy nie będzie sprawdzana. Zasoby, które będą wyświetlane przy użyciu tej strategii, muszą zostać dodane do pamięci podręcznej przed przesłaniem żądania.

Najpierw pamięć podręczna

Korzystając z tej strategii, skrypt service worker szuka pasującego żądania w pamięci podręcznej i zwraca odpowiednią odpowiedź, jeśli jest ona w niej zapisana. 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 sieciowej, żądanie zakończy się błędem. Wyświetlanie komponentów bez wysyłania żądania do sieci jest zwykle szybsze, dlatego ta strategia stawia na wydajność, a nie na aktualność.

Strategia „Najpierw pamięć podręczna”

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ć

Ta strategia jest przeciwieństwem strategii „Najpierw pamięć podręczna”. Sprawdza, czy żądanie można zrealizować z sieci, a jeśli nie, próbuje pobrać je z pamięci podręcznej. np. najpierw pamięć podręczna. Jeśli nie ma odpowiedzi sieci ani odpowiedzi z pamięci podręcznej, żądanie zakończy się błędem. Pobieranie odpowiedzi z sieci jest zwykle wolniejsze niż pobieranie jej z pamięci podręcznej. Ta strategia priorytetowo traktuje aktualne treści zamiast wydajności.

Strategia „Najpierw sieć”

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

Nieaktualne podczas ponownego sprawdzania

Strategia „nieaktualne podczas ponownej weryfikacji” natychmiast zwraca odpowiedź z pamięci podręcznej, a następnie sprawdza, czy w sieci jest dostępna aktualizacja. Jeśli ją znajdzie, zastępuje nią odpowiedź z pamięci podręcznej. Ta strategia zawsze wysyła żądanie sieciowe, ponieważ nawet jeśli znajdzie zasób w pamięci podręcznej, spróbuje zaktualizować to, co było w pamięci podręcznej, za pomocą tego, co zostało odebrane z sieci, aby użyć zaktualizowanej wersji w kolejnym żądaniu. Dzięki temu możesz korzystać z szybkiego wyświetlania treści z pamięci podręcznej, a jednocześnie aktualizować ją w tle.

Strategia nieaktualne podczas ponownej weryfikacji

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 „tylko sieć” jest podobna do działania przeglądarek bez skryptu service worker lub interfejsu Cache Storage API. Żądania zwracają zasób tylko wtedy, gdy można go pobrać z sieci. Jest to często przydatne w przypadku zasobów takich jak żądania interfejsu API dostępne tylko online.

Strategia „Tylko sieć”

Tylko pamięć podręczna

Strategia „Tylko pamięć podręczna” gwarantuje, że żądania nigdy nie są wysyłane do sieci. Na wszystkie przychodzące żądania odpowiada się za pomocą wstępnie wypełnionego elementu pamięci podręcznej. Poniższy kod używa fetch do obsługi zdarzeń z metodą match pamięci podręcznej, aby odpowiadać tylko z pamięci podręcznej:

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

Strategia tylko pamięci podręcznej.

Strategie niestandardowe

Powyższe strategie buforowania są powszechnie stosowane, ale to Ty odpowiadasz za skrypt service worker i sposób obsługi żądań. Jeśli żaden z nich nie odpowiada Twoim potrzebom, utwórz własny.

Możesz na przykład użyć strategii „najpierw sieć” z limitem czasu, aby nadać priorytet zaktualizowanym treściom, ale tylko wtedy, gdy odpowiedź pojawi się w ustawionym przez Ciebie progu. Możesz też połączyć odpowiedź z pamięci podręcznej z odpowiedzią z sieci i utworzyć złożoną odpowiedź z poziomu service workera.

Aktualizowanie komponentów

Aktualizowanie zapisanych w pamięci podręcznej zasobów aplikacji PWA może być trudne. Strategia „nieaktualne podczas ponownej weryfikacji” to jeden ze sposobów na to, ale nie jedyny. W rozdziale poświęconym aktualizacjom poznasz różne techniki aktualizowania treści i zasobów aplikacji.

Zasoby