W niektórych sytuacjach mechanizm Service Worker musi aktywnie komunikować się z dowolną z kontrolowanych kart, aby poinformować o określonym zdarzeniu. Przykłady:
- Powiadomienie strony o zainstalowaniu nowej wersji skryptu service worker, tak aby użytkownik mógł zobaczyć przycisk „Zaktualizuj, aby odświeżyć” umożliwiający natychmiastowy dostęp do nowej funkcji.
- Poinformuj użytkownika o zmianie w danych w pamięci podręcznej po stronie skryptu service worker, pokazując na przykład takie oznaczenie: „Aplikacja jest teraz gotowa do pracy w trybie offline” lub „Dostępna nowa wersja treści”.
Takie przypadki użycia nazywamy „aktualizacjami strumieniowymi”, dzięki którym mechanizm Service Worker nie potrzebuje komunikatu ze strony, aby rozpocząć komunikację. W tym przewodniku omówimy różne sposoby wdrażania tego typu komunikacji między stronami a mechanizmami Service Worker przy użyciu standardowych interfejsów API przeglądarki i biblioteki Workbox.
Przypadki produkcyjne
Tinder
PWA Tinder używa workbox-window
, aby nasłuchiwać ważnych momentów cyklu życia skryptu service worker z strony („zainstalowano”, „kontrolowana” i „aktywowano”). Dzięki temu, gdy nowy skrypt service worker pojawia się, wyświetla się baner „Aktualizacja dostępna”, aby można było odświeżyć aplikację PWA i uzyskać dostęp do najnowszych funkcji:
Dynia
Gdy skrypt Squoosh PWA zapisze w pamięci podręcznej wszystkie zasoby niezbędne do działania w trybie offline, wysyła na stronę komunikat „Gotowe do pracy w trybie offline”, który informuje użytkownika o tej funkcji:
Korzystanie z Workbox
Nasłuchiwanie zdarzeń cyklu życia skryptu service worker
workbox-window
ma prosty interfejs umożliwiający wychwytywanie ważnych zdarzeń cyklu życia skryptu service worker.
Biblioteka używa interfejsów API po stronie klienta, takich jak updatefound
i statechange, oraz udostępnia detektor zdarzeń wyższego poziomu w obiekcie workbox-window
, co ułatwia użytkownikowi korzystanie z tych zdarzeń.
Ten kod strony pozwala wykryć każdą nową wersję skryptu service worker, by przekazać ją użytkownikowi:
const wb = new Workbox('/sw.js');
wb.addEventListener('installed', (event) => {
if (event.isUpdate) {
// Show "Update App" banner
}
});
wb.register();
Poinformuj stronę o zmianach w danych pamięci podręcznej
Pakiet Workbox workbox-broadcast-update
to standardowy sposób powiadamiania klientów okien o zaktualizowaniu odpowiedzi zapisanej w pamięci podręcznej. Ta metoda jest najczęściej używana w połączeniu ze strategią StaleGdyRevalidate.
Aby transmitować aktualizacje, dodaj broadcastUpdate.BroadcastUpdatePlugin
do opcji strategii po stronie skryptu service worker:
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ń, na przykład:
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 dostarczane przez Workbox nie wystarczają do Twoich potrzeb, możesz wdrożyć „aktualizacje transmisji” za pomocą tych interfejsów API przeglądarki:
Interfejs Broadcast Channel API
Skrypt service worker tworzy obiekt BroadcastChannel i wysyłać do niego wiadomości. Każdy kontekst (np. strona) zainteresowany odebraniem tych wiadomości może utworzyć instancję BroadcastChannel
i wdrożyć moduł obsługi wiadomości do odbierania wiadomości.
Aby poinformować stronę o instalowaniu 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 odsłuchuje te zdarzenia, subskrybując sw-update-channel
:
// 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.
}
};
Jest to prosta technika, ale jej ograniczeniem jest obsługa przeglądarek: w tej chwili Safari nie obsługuje tego interfejsu API.
Interfejs API klienta
Interfejs Client API zapewnia prosty sposób komunikacji z wieloma klientami z poziomu skryptu service worker przez powtarzanie tablicy obiektów Client
.
Użyj tego kodu skryptu service worker, aby wysłać wiadomość do ostatniej zaznaczonej karty:
// 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 ma wbudowany moduł obsługi wiadomości, który przechwytuje te wiadomości:
// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
// Process response
}
};
Interfejs API klienta doskonale sprawdza się w przypadkach takich jak przekazywanie informacji do wielu aktywnych kart. Interfejs API jest obsługiwany przez wszystkie popularne przeglądarki, ale nie wszystkie jego metody są w niej obsługiwane. Zanim z niej skorzystasz, sprawdź jej obsługę.
Kanał wiadomości
Kanał wiadomości wymaga wstępnej konfiguracji, czyli przekazania portu ze strony do skryptu service worker w celu nawiązania między nimi kanału komunikacji. Strona tworzy instancję obiektu MessageChannel
i przekazuje port do skryptu service worker przez interfejs postMessage()
:
const messageChannel = new MessageChannel();
// Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
messageChannel.port2,
]);
Strona nasłuchuje wiadomości, implementując moduł obsługi „onmessage” na tym porcie:
// Listen to messages
messageChannel.port1.onmessage = (event) => {
// Process message
};
Skrypt service worker odbiera port i zapisuje do niego odniesienie:
// 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 na stronę, wywołując postMessage()
w odniesieniu do portu:
// Communicate
communicationPort.postMessage({type: 'MSG_ID' });
Implementacja MessageChannel
może być bardziej złożona ze względu na potrzebę inicjowania portów, ale jest obsługiwana przez wszystkie główne przeglądarki.
Dalsze kroki
W tym przewodniku omawiamy jeden konkretny przypadek komunikacji Window to Service Worker: „aktualizacje w transmisji”. Obejmuje to nasłuchiwanie ważnych zdarzeń cyklu życia mechanizmów Service Worker i komunikowanie się ze stroną na temat zmian w treści lub danych w pamięci podręcznej. Możesz rozważyć bardziej interesujące przypadki użycia, w których skrypt service worker aktywnie komunikuje się ze stroną, ale nie otrzymuje wcześniej żadnych komunikatów.
Więcej wzorców komunikacji między oknami i skryptami service worker znajdziesz w tych dokumentach:
- Przewodnik po buforowaniu: wywoływanie skryptu service worker ze strony w celu wcześniejszego buforowania zasobów (np. w sytuacjach pobierania z wyprzedzeniem).
- Dwukierunkowa komunikacja: przekazywanie zadania skryptowi service worker (np. bardzo intensywne pobieranie) i informowanie strony o postępach.