In alcuni scenari, il worker di servizio potrebbe dover comunicare in modo proattivo con una delle schede attive che controlla per informare di un determinato evento. Ecco alcuni esempi:
- Informa la pagina quando è stata installata una nuova versione del service worker, in modo che possa mostrare all'utente un pulsante "Aggiorna per aggiornare" per accedere immediatamente alla nuova funzionalità.
- Comunicare all'utente una modifica ai dati memorizzati nella cache avvenuta lato service worker, mostrando un'indicazione, ad esempio: "L'app è ora pronta per il funzionamento offline" o "Nuova versione dei contenuti disponibile".
Chiameremo "aggiornamento di trasmissione" questi tipi di casi d'uso in cui il service worker non deve ricevere un messaggio dalla pagina per avviare una comunicazione. In questa guida esamineremo diversi modi per implementare questo tipo di comunicazione tra pagine e worker di servizio utilizzando le API browser standard e la libreria Workbox.
Casi di produzione
Tinder
La PWA di Tinder utilizza workbox-window
per ascoltare i momenti importanti del ciclo di vita del servizio worker dalla pagina ("installato", "controllato" e "attivato"). In questo modo, quando viene attivato un nuovo worker di servizio, viene visualizzato un banner "Aggiornamento disponibile", in modo che l'utente possa aggiornare la PWA e accedere alle ultime funzionalità:
Squoosh
Nella PWA di Squioosh, quando il service worker ha memorizzato nella cache tutti gli asset necessari per il funzionamento offline, invia un messaggio alla pagina per mostrare un messaggio popup "Pronta per il lavoro offline", che comunica all'utente la funzionalità:
Utilizzo di Workbox
Ascoltare gli eventi del ciclo di vita del worker di servizio
workbox-window
fornisce un'interfaccia semplice per ascoltare gli eventi importanti del ciclo di vita dei service worker.
Sotto il cofano, la libreria utilizza API lato client come
updatefound
e statechange
e fornisce ascoltatori di eventi di livello superiore nell'oggetto workbox-window
, semplificando per l'
utente l'utilizzo di questi eventi.
Il seguente codice pagina consente di rilevare ogni volta che viene installata una nuova versione del servizio worker, in modo da comunicarlo all'utente:
const wb = new Workbox('/sw.js');
wb.addEventListener('installed', (event) => {
if (event.isUpdate) {
// Show "Update App" banner
}
});
wb.register();
Informa la pagina delle modifiche ai dati della cache
Il pacchetto Workbox
workbox-broadcast-update
fornisce un modo standard per notificare ai client Windows che una risposta memorizzata nella cache è stata aggiornata. Viene solitamente utilizzata insieme alla strategia StaleWhileRevalidate.
Per trasmettere gli aggiornamenti, aggiungi un broadcastUpdate.BroadcastUpdatePlugin
alle opzioni di strategia nel lato del servizio 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(),
],
})
);
Nella tua app web, puoi ascoltare questi eventi nel seguente modo:
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();
}
});
Utilizzo delle API del browser
Se le funzionalità fornite da Workbox non sono sufficienti per le tue esigenze, utilizza le seguenti API browser per implementare gli "aggiornamenti di trasmissione":
API Broadcast Channel
Il service worker crea un oggetto BroadcastChannel e inizia a inviargli messaggi. Qualsiasi contesto (ad es. una pagina) interessato a ricevere questi messaggi può istanziare un oggetto BroadcastChannel
e implementare un gestore dei messaggi per riceverli.
Per informare la pagina quando viene installato un nuovo worker di servizio, utilizza il seguente codice:
// 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'});
});
La pagina ascolta questi eventi sottoscrivendo l'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.
}
};
Si tratta di una tecnica semplice, ma la sua limitazione è il supporto del browser: al momento in cui scriviamo, Safari non supporta questa API.
API client
L'API client fornisce un modo semplice per comunicare con più client dal servizio worker iterando su un array di oggetti Client
.
Utilizza il seguente codice di worker di servizio per inviare un messaggio all'ultima scheda attivata:
// 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'});
}
});
La pagina implementa un gestore dei messaggi per intercettare questi messaggi:
// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
// Process response
}
};
L'API client è un'ottima opzione per casi come la trasmissione di informazioni a più schede attive. L'API è supportata da tutti i principali browser, ma non tutti i relativi metodi. Verifica la compatibilità del browser prima di usarlo.
Canale messaggi
Canale di messaggi richiede un passaggio di configurazione iniziale, passando una porta dalla pagina al servizio worker, per stabilire un canale di comunicazione tra i due. La pagina esegue l'inizializzazione di un oggetto MessageChannel
e passa un
porto al service worker tramite l'interfaccia postMessage()
:
const messageChannel = new MessageChannel();
// Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
messageChannel.port2,
]);
La pagina ascolta i messaggi implementando un gestore "onmessage" su quella porta:
// Listen to messages
messageChannel.port1.onmessage = (event) => {
// Process message
};
Il service worker riceve la porta e ne salva un riferimento:
// Initialize
let communicationPort;
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'PORT_INITIALIZATION') {
communicationPort = event.ports[0];
}
});
A questo punto può inviare messaggi alla pagina chiamando postMessage()
nel riferimento alla porta:
// Communicate
communicationPort.postMessage({type: 'MSG_ID' });
MessageChannel
potrebbe essere più complesso da implementare, a causa della necessità di inizializzare le porte, ma è supportato da tutti i principali browser.
Passaggi successivi
In questa guida abbiamo esplorato un caso particolare di comunicazione tra finestra e worker di servizio: "aggiornamento di trasmissione". Gli esempi esplorati includono l'ascolto di eventi importanti del ciclo di vita del servizio worker e la comunicazione alla pagina delle modifiche ai contenuti o ai dati memorizzati nella cache. Puoi pensare a casi d'uso più interessanti in cui il worker di servizio comunica in modo proattivo con la pagina senza aver ricevuto alcun messaggio in precedenza.
Per altri pattern di comunicazione tra Window e service worker, consulta:
- Guida alla memorizzazione nella cache imperativa: chiamata di un service worker dalla pagina per memorizzare in cache le risorse in anticipo (ad es. in scenari di pre-caricamento).
- Comunicazione bidirezionale: delega di un'attività a un worker di servizio (ad es. un download impegnativo) e aggiornamento della pagina sullo stato di avanzamento.