Rozgłaszaj aktualizacje stron z skryptami service worker

Andrew Guan
Andrew Guan

W niektórych przypadkach może być konieczne, aby usługa komunikowała się aktywnie z aktywnymi kartami, nad którymi ma kontrolę, w celu poinformowania o określonym zdarzeniu. Przykłady:

  • Informowanie strony o zainstalowaniu nowej wersji pracownika usługi, aby mogła ona wyświetlić użytkownikowi przycisk „Aktualizuj, aby odświeżyć”, umożliwiający natychmiastowy dostęp do nowej funkcji.
  • Poinformowanie użytkownika o zmianie danych w pamięci podręcznej, która nastąpiła po stronie service workera, przez wyświetlenie komunikatu, takiego jak „Aplikacja jest teraz gotowa do pracy w trybie offline” lub „Dostępna nowa wersja treści”.
Diagram pokazujący, jak serwis worker komunikuje się ze stroną, aby wysłać aktualizację.

Tego typu przypadki użycia będziemy nazywać „aktualizacjami transmisji”, które nie muszą otrzymywać wiadomości ze strony, aby rozpocząć komunikację. W tym przewodniku omówimy różne sposoby implementowania tego typu komunikacji między stronami a usługami w tle, korzystając ze standardowych interfejsów API przeglądarki i biblioteki Workbox.

Przypadki produkcyjne

Tinder

PWA Tinder wykorzystuje workbox-window do nasłuchiwania ważnych momentów w cyklu życia instancji roboczych usługi („zainstalowano”, „kontrolowane” i „aktywowane”). Dzięki temu, gdy pojawia się nowy skrypt service worker, wyświetla się baner „Dostępna aktualizacja”, umożliwiając odświeżenie PWA i uzyskiwanie dostępu do najnowszych funkcji:

Zrzut ekranu przedstawiający funkcję „Dostępna aktualizacja” w aplikacji internetowej Tinder.
W przypadku Tindera w PWA skrypt service worker informuje stronę, że nowa wersja jest gotowa, a strona wyświetla użytkownikom baner „Dostępna aktualizacja”.

Squoosh

W przypadku PWA w Squoosh, gdy usługa w tle ma w pamięci podręcznej wszystkie niezbędne zasoby do działania offline, wysyła do strony wiadomość, aby wyświetlić powiadomienie „Gotowe do pracy offline”, informujące użytkownika o tej funkcji:

Zrzut ekranu przedstawiający funkcję aplikacji internetowej Squoosh „Gotowa do pracy w trybie offline”.
W PWA Squoosh usługa workera rozgłasza na stronie aktualizację, gdy pamięć podręczna jest gotowa, a strona wyświetla komunikat „Gotowe do pracy offline”.

Korzystanie z Workbox

Nasłuchiwanie zdarzeń cyklu życia usługi workera

workbox-window udostępnia prosty interfejs do nasłuchiwania ważnych zdarzeń cyklu życia skryptu service worker. Biblioteka korzysta z interfejsów API po stronie klienta, takich jak updatefoundstatechange, oraz udostępnia obiekt workbox-window z odbiorcami zdarzeń wyższego poziomu, co ułatwia użytkownikowi korzystanie z tych zdarzeń.

Poniższy kod strony umożliwia wykrywanie każdego zainstalowania nowej wersji usługi działającej w tle, aby można było poinformować o tym użytkownika:

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

wb.addEventListener('installed', (event) => {
  if (event.isUpdate) {
    // Show "Update App" banner
  }
});

wb.register();

Informuj stronę o zmianach w danych pamięci podręcznej

Pakiet Workbox workbox-broadcast-update zapewnia standardowy sposób powiadamiania klientów okien o zaktualizowaniu odpowiedzi z pamięci podręcznej. Jest ona najczęściej używana razem ze strategią StaleWhileRevalidate.

Aby przesyłać aktualizacje, dodaj opcję broadcastUpdate.BroadcastUpdatePlugin do opcji strategii po stronie pracownika:

import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
import {BroadcastUpdatePlugin} from 'workbox-broadcast-update';

registerRoute(
  ({url}) => url.pathname.startsWith('/api/'),
  new StaleWhileRevalidate({
    plugins: [
      new BroadcastUpdatePlugin(),
    ],
  })
);

W aplikacji internetowej możesz nasłuchiwać tych zdarzeń w ten sposób:

navigator.serviceWorker.addEventListener('message', async (event) => {
  // Optional: ensure the message came from workbox-broadcast-update
  if (event.data.meta === 'workbox-broadcast-update') {
    const {cacheName, updatedUrl} = event.data.payload;

    // Do something with cacheName and updatedUrl.
    // For example, get the cached content and update
    // the content on the page.
    const cache = await caches.open(cacheName);
    const updatedResponse = await cache.match(updatedUrl);
    const updatedText = await updatedResponse.text();
  }
});

Korzystanie z interfejsów API przeglądarek

Jeśli funkcje Workbox nie wystarczają do Twoich potrzeb, użyj tych interfejsów API przeglądarki, aby zaimplementować „aktualizacje rozsyłane”:

Interfejs Broadcast Channel API

Skrypt service worker tworzy obiekt BroadcastChannel i zaczyna wysyłać do niego wiadomości. Każdy kontekst (np. strona) zainteresowany odbieraniem tych wiadomości może utworzyć instancję obiektu BroadcastChannel i zaimplementować w nim element obsługi wiadomości.

Aby poinformować stronę o zainstalowaniu nowego skryptu service worker, użyj tego kodu:

// Create Broadcast Channel to send messages to the page
const broadcast = new BroadcastChannel('sw-update-channel');

self.addEventListener('install', function (event) {
  // Inform the page every time a new service worker is installed
  broadcast.postMessage({type: 'CRITICAL_SW_UPDATE'});
});

Strona nasłuchuje tych zdarzeń, subskrybując te zdarzenia:

// Create Broadcast Channel and listen to messages sent to it
const broadcast = new BroadcastChannel('sw-update-channel');

broadcast.onmessage = (event) => {
  if (event.data && event.data.type === 'CRITICAL_SW_UPDATE') {
    // Show "update to refresh" banner to the user.
  }
};

To prosta metoda, ale jej ograniczeniem jest obsługa przez przeglądarki: w momencie pisania tego artykułu Safari nie obsługuje tego interfejsu API.

Client API

Interfejs API klienta zapewnia prosty sposób komunikowania się z wieloma klientami z poziomu service workera przez iterowanie w tablicy obiektów Client.

Aby wysłać wiadomość do ostatniej aktywnej karty, użyj tego kodu usługi:

// Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
  if (clients && clients.length) {
    // Respond to last focused tab
    clients[0].postMessage({type: 'MSG_ID'});
  }
});

Strona implementuje moduł obsługi wiadomości, aby przechwytywać te wiadomości:

// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
     if (event.data && event.data.type === 'MSG_ID') {
         // Process response
   }
};

Interfejs Client API doskonale nadaje się do przesyłania informacji na wiele aktywnych kart. Interfejs API jest obsługiwany przez wszystkie popularne przeglądarki, ale nie wszystkie dostępne metody tak. Przed użyciem sprawdź, czy Twoja przeglądarka obsługuje tę funkcję.

Kanał wiadomości

Kanał wiadomości wymaga wstępnej konfiguracji polegającej na przekazaniu portu ze strony do usługi internetowej, aby ustanowić kanał komunikacji między nimi. Strona tworzy instancję obiektu MessageChannel i przekazuje skryptowi service worker interfejs postMessage():

const messageChannel = new MessageChannel();

// Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
  messageChannel.port2,
]);

Strona nasłuchuje wiadomości, implementując na tym porcie uchwyt za pomocą metody „onmessage”:

// Listen to messages
messageChannel.port1.onmessage = (event) => {
  // Process message
};

Skrypt service worker odbiera port i zapisuje do niego odwołanie:

// Initialize
let communicationPort;

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PORT_INITIALIZATION') {
    communicationPort = event.ports[0];
  }
});

Od tego momentu może wysyłać wiadomości do strony, wywołując postMessage() w odniesieniu do portu:

// Communicate
communicationPort.postMessage({type: 'MSG_ID' });

MessageChannel może być trudniejszy do wdrożenia ze względu na konieczność inicjowania portów, ale jest obsługiwany przez wszystkie główne przeglądarki.

Dalsze kroki

W tym przewodniku omówiliśmy jeden konkretny przypadek komunikacji z użyciem okna dla usług: „aktualizacje w ramach transmisji”. W przykładach omawianych w tym artykule uwzględniono m.in. słuchanie ważnych zdarzeń cyklu życia usługi oraz komunikowanie się z stroną o zmianach w treści lub danych w pamięci podręcznej. Możesz wymyślić bardziej interesujące przypadki użycia, w których usługa robocza komunikuje się z witryną w sposób proaktywny, bez wcześniejszego otrzymywania wiadomości.

Więcej wzorów komunikacji między oknem a usługą znajdziesz w tych artykułach:

Dodatkowe materiały