In alcuni casi, un'app web potrebbe dover stabilire un canale di comunicazione doppio tra e il service worker.
Ad esempio, nella PWA di un podcast si potrebbe creare una funzionalità che consenta all'utente di scaricare le puntate per il consumo offline e consentire al service worker di mantenere la pagina regolarmente informata dell'avanzamento, in modo che il thread può aggiornare la UI.
In questa guida esploreremo i diversi modi per implementare una comunicazione relativa tra Window e service worker, esplorando il contesto API diverse, la libreria Workbox alcuni casi avanzati.
Utilizzo di Workbox
workbox-window
è un insieme di
della libreria Workbox previsti
per l'esecuzione nel contesto della finestra. La Workbox
fornisce un metodo messageSW()
per inviare un messaggio al service worker registrato dell'istanza e
e attendere una risposta.
Il seguente codice di pagina crea una nuova istanza Workbox
e invia un messaggio al service worker
per ottenerne la versione:
const wb = new Workbox('/sw.js');
wb.register();
const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);
Il service worker implementa un listener di messaggi dall'altra parte e risponde all'input registrato service worker:
const SW_VERSION = '1.0.0';
self.addEventListener('message', (event) => {
if (event.data.type === 'GET_VERSION') {
event.ports[0].postMessage(SW_VERSION);
}
});
All'inizio, la libreria utilizza un'API del browser che esamineremo nella prossima sezione: Messaggio Channel, ma astrae molti i dettagli dell'implementazione, semplificando l'utilizzo e sfruttando al contempo il browser largo supportato dell'API.
Utilizzo delle API del browser
Se la libreria Workbox non è sufficiente per le tue esigenze, sono disponibili diverse API di livello inferiore implementare la comunicazione "due vie" tra le pagine e i service worker. Hanno alcune somiglianze e le differenze:
Analogie:
- In tutti i casi la comunicazione inizia da un lato tramite l'interfaccia di
postMessage()
e viene ricevuta dall'altra parte implementando un gestoremessage
. - In pratica, tutte le API disponibili ci consentono di implementare gli stessi casi d'uso, ma alcuni può semplificare lo sviluppo in alcuni scenari.
Differenze:
- Hanno diversi modi per identificare l'altro lato della comunicazione: alcuni usano riferimento esplicito all'altro contesto, mentre gli altri possono comunicare implicitamente tramite un proxy su ciascun lato.
- Il supporto del browser varia da un browser all'altro.
API Broadcast Channel
L'API Broadcast Channel consente la comunicazione di base tra contesti di navigazione tramite BroadcastChannel oggetti.
Per implementarlo, innanzitutto ogni contesto deve creare un'istanza di un oggetto BroadcastChannel
con lo stesso ID
e inviare e ricevere messaggi:
const broadcast = new BroadcastChannel('channel-123');
L'oggetto BroadcastChannel espone un'interfaccia postMessage()
per inviare un messaggio a qualsiasi ascolto
contesto:
//send message
broadcast.postMessage({ type: 'MSG_ID', });
Qualsiasi contesto del browser può ascoltare i messaggi con il metodo onmessage
dell'BroadcastChannel
:
//listen to messages
broadcast.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process message...
}
};
Come abbiamo visto, non c'è alcun riferimento esplicito a un particolare contesto, quindi non c'è bisogno di ottenere una fare riferimento prima al service worker o a qualsiasi client specifico.
Lo svantaggio è che, al momento della stesura del presente documento, l'API supporta Chrome, Firefox ed Edge, ma altri browser, come Safari, non lo supportano .
API client
L'API client ti consente di ottenere
riferimento a tutti gli oggetti WindowClient
che rappresentano le schede attive controllate dal service worker.
Poiché la pagina è controllata da un singolo service worker, questa ascolta e invia messaggi a
service worker attivo direttamente tramite l'interfaccia serviceWorker
:
//send message
navigator.serviceWorker.controller.postMessage({
type: 'MSG_ID',
});
//listen to messages
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process response
}
};
Allo stesso modo, il service worker ascolta i messaggi implementando un listener onmessage
:
//listen to messages
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//Process message
}
});
Per comunicare con uno qualsiasi dei suoi client, il service worker ottiene un array di
WindowClient
oggetti mediante l'esecuzione
come quelli
Clients.matchAll()
e
Clients.get()
Può quindi
postMessage()
uno qualsiasi:
//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'});
}
});
Client API
è una buona opzione per comunicare facilmente con tutte le schede attive di un service worker
in modo relativamente semplice. L'API è supportata da tutti i principali
browser,
ma non tutti i metodi potrebbero essere disponibili, quindi assicurati di controllare il supporto del browser prima
a implementarla sul tuo sito.
Canale messaggi
Message Channel richiede la definizione e il passaggio di una porta da un contesto all'altro per stabilire una comunicazione doppio canale.
Per inizializzare il canale, la pagina crea un'istanza di un oggetto MessageChannel
e lo utilizza
per inviare una porta al service worker registrato. La pagina implementa anche un listener onmessage
su
per ricevere messaggi dall'altro contesto:
const messageChannel = new MessageChannel();
//Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
messageChannel.port2,
]);
//Listen to messages
messageChannel.port1.onmessage = (event) => {
// Process message
};
Il service worker riceve la porta, la salva un riferimento e lo utilizza per inviare un messaggio all'altro lato:
let communicationPort;
//Save reference to port
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'PORT_INITIALIZATION') {
communicationPort = event.ports[0];
}
});
//Send messages
communicationPort.postMessage({type: 'MSG_ID'});
MessageChannel
è attualmente supportato da tutti i principali
browser supportati.
API avanzate: sincronizzazione e recupero in background
In questa guida abbiamo esplorato i modi per implementare tecniche di comunicazione due vie, relativamente casi semplici, come passare un messaggio in formato stringa che descriva l'operazione da eseguire o un elenco di URL memorizzare nella cache da un contesto all'altro. In questa sezione esploreremo due API per gestire scenari: assenza di connettività e download di lunga durata.
Sincronizzazione in background
Un'app di chat potrebbe assicurarsi che i messaggi non vadano mai persi a causa di problemi di connettività. La L'API Background Sync consente di rimandare le azioni da riprovare quando la connettività dell'utente è stabile. Questo è utile per garantire viene inviato effettivamente ciò che l'utente vuole inviare.
Anziché l'interfaccia postMessage()
, la pagina registra un sync
:
navigator.serviceWorker.ready.then(function (swRegistration) {
return swRegistration.sync.register('myFirstSync');
});
Il service worker rimane quindi in ascolto dell'evento sync
per elaborare il messaggio:
self.addEventListener('sync', function (event) {
if (event.tag == 'myFirstSync') {
event.waitUntil(doSomeStuff());
}
});
La funzione doSomeStuff()
deve restituire una promessa che indica l'esito positivo o negativo di qualsiasi cosa
cercando di fare. Se viene evaso, la sincronizzazione è completa. Se non riesce, verrà pianificata un'altra sincronizzazione su
riprova. Anche i nuovi tentativi di sincronizzazione attendono la connettività e utilizzano un backoff esponenziale.
Una volta eseguita l'operazione, il service worker può comunicare con la pagina aggiornare la UI, utilizzando una qualsiasi delle API di comunicazione illustrate in precedenza.
La Ricerca Google utilizza la sincronizzazione in background per conservare le query non riuscite a causa di una cattiva connettività e riprovare in un secondo momento, quando l'utente sarà online. Una volta eseguita l'operazione, comunicano il risultato a l'utente tramite una notifica push web:
Recupero in background
Per operazioni relativamente brevi come l'invio di un messaggio o un elenco di URL da memorizzare nella cache, le opzioni esplorati finora sono una buona scelta. Se l'attività richiede troppo tempo, il browser terminerà il servizio personale, altrimenti rischia la privacy e la batteria dell'utente.
L'API Background Fetch ti consente di trasferire a un service worker un'attività lunga, come il download di film, podcast o livelli di un gioco.
Per comunicare con il service worker dalla pagina, usa backgroundFetch.fetch
, anziché
postMessage()
:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.fetch(
'my-fetch',
['/ep-5.mp3', 'ep-5-artwork.jpg'],
{
title: 'Episode 5: Interesting things.',
icons: [
{
sizes: '300x300',
src: '/ep-5-icon.png',
type: 'image/png',
},
],
downloadTotal: 60 * 1024 * 1024,
},
);
});
L'oggetto BackgroundFetchRegistration
consente alla pagina di ascoltare l'evento progress
da seguire
avanzamento del download:
bgFetch.addEventListener('progress', () => {
// If we didn't provide a total, we can't provide a %.
if (!bgFetch.downloadTotal) return;
const percent = Math.round(
(bgFetch.downloaded / bgFetch.downloadTotal) * 100,
);
console.log(`Download progress: ${percent}%`);
});
.
Passaggi successivi
In questa guida abbiamo esplorato il caso più generale di comunicazione tra page e service worker (comunicazione bidirezionale).
Molte volte, è possibile che una persona abbia bisogno di un solo contesto per comunicare con l'altro, senza ricevere risposta. Consulta le seguenti guide per indicazioni su come implementare le tecniche unidirezionali nelle le tue pagine da e al service worker, insieme a casi d'uso ed esempi di produzione:
- Guida alla memorizzazione nella cache imperativa: chiamata a un service worker dalla pagina a cache in anticipo (ad es. in scenari di precaricamento).
- Annunci di aggiornamento: chiamata alla pagina dal service worker per informare su aggiornamenti importanti (ad es. è disponibile una nuova versione dell'app web).