W niektórych przypadkach może być konieczne, aby usługa komunikowała się aktywnie z aktywnymi kartami, które kontroluje, aby poinformować 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”.
Takie przypadki użycia to sytuacje, w których pracownik usługi nie musi otrzymywać wiadomości od strony, aby rozpocząć komunikację „transmisją aktualizacji”. 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
Tinder PWA używa workbox-window
do nasłuchiwania ważnych momentów cyklu życia usługi na stronie (np. „zainstalowana”, „kontrolowana” i „aktywowana”). Gdy nowy serwis działający w tle zostanie uruchomiony, wyświetli się baner „Dostępna aktualizacja”, dzięki któremu użytkownicy będą mogli odświeżyć PWA i uzyskać dostęp do najnowszych funkcji:
Squoosh
W PWA Squish, gdy usługa wtyczki jest w stanie zapisać w pamięci podręcznej wszystkie niezbędne zasoby, aby działać w trybie offline, wysyła na stronę wiadomość, aby wyświetlić komunikat „Gotowe do pracy offline” i poinformować użytkownika o tej funkcji:
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 updatefound
i statechange, 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();
Informowanie strony 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 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 spełniają Twoich potrzeb, możesz użyć 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 pracownika usługi, 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: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.
}
};
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 Client API 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 element 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 to świetna opcja w przypadku rozpowszechniania informacji na wielu aktywnych kartach. Interfejs API jest obsługiwany przez wszystkie główne przeglądarki, ale nie wszystkie jego metody. 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:
- Przewodnik po pamięci podręcznej imperatywnej: wywołanie skryptu service worker ze strony w celu wcześniejszego zapisania zasobów w pamięci podręcznej (np. w scenariuszach wstępnego pobierania).
- Komunikacja dwukierunkowa: delegowanie zadania do usługi internetowej (np. pobieranie dużych plików) i informowanie strony o postępach.