L'API BroadcastChannel consente agli script della stessa origine di inviare messaggi ad altri contesti di navigazione. Può essere pensato come un semplice bus di messaggi che consente la semantica Pub/Sub tra finestre/schede, iframe, web worker e service worker.
Nozioni di base sulle API
L'API Broadcast Channel è un'API semplice che semplifica la comunicazione tra i contesti di navigazione. cioè comunicare tra finestre/schede, iframe, web worker e service worker. I messaggi pubblicati su un determinato canale vengono inviati a tutti gli ascoltatori di quel canale.
Il costruttore BroadcastChannel
utilizza un singolo parametro: il nome di un canale.
Il nome identifica il canale e si adatta ai vari contesti di navigazione.
// Connect to the channel named "my_bus".
const channel = new BroadcastChannel('my_bus');
// Send a message on "my_bus".
channel.postMessage('This is a test message.');
// Listen for messages on "my_bus".
channel.onmessage = function(e) {
console.log('Received', e.data);
};
// Close the channel when you're done.
channel.close();
l'invio di un messaggio e un altro
I messaggi possono essere stringhe o qualsiasi altro supporto supportato dall'algoritmo del clone strutturato (stringhe, oggetti, array, BLOB, array buffer, mappa).
Esempio - invio di un BLOB o file
channel.postMessage(new Blob(['foo', 'bar'], {type: 'plain/text'}));
Un canale non viene trasmesso a se stesso. Pertanto, se hai un listener onmessage
sulla stessa pagina di un postMessage()
per lo stesso canale, l'evento message
non si accende.
Differenze con altre tecniche
A questo punto ti starai chiedendo in che modo ciò riguarda altre tecniche per la trasmissione dei messaggi come WebSocket, SharedWorkers, l'API MessageChannel
e window.postMessage()
. L'API Broadcast Channel non sostituisce queste API. Ognuna ha uno scopo. L'API Broadcast Channel è progettata per facilitare la comunicazione one-to-many tra gli script sulla stessa origine.
Alcuni casi d'uso per i canali televisivi:
- Rileva le azioni degli utenti in altre schede
- Scopri quando un utente accede a un account in un'altra finestra/scheda.
- Chiedi a un worker di eseguire alcuni lavori in background
- Scoprire quando un servizio esegue un'azione.
- Quando l'utente carica una foto in una finestra, falla passare ad altre pagine aperte.
Esempio: pagina che capisce quando l'utente si disconnette, anche da un'altra scheda aperta sullo stesso sito:
<button id="logout">Logout</button>
<script>
function doLogout() {
// update the UI login state for this page.
}
const authChannel = new BroadcastChannel('auth');
const button = document.querySelector('#logout');
button.addEventListener('click', e => {
// A channel won't broadcast to itself so we invoke doLogout()
// manually on this page.
doLogout();
authChannel.postMessage({cmd: 'logout', user: 'Eric Bidelman'});
});
authChannel.onmessage = function(e) {
if (e.data.cmd === 'logout') {
doLogout();
}
};
</script>
In un altro esempio, supponiamo che tu voglia chiedere a un service worker di rimuovere
contenuti memorizzati nella cache dopo che l'utente ha modificato la propria "impostazione di archiviazione offline" all'interno dell'app.
Potresti eliminare le cache utilizzando window.caches
, ma il service worker potrebbe
contengono già un'utilità per farlo. Possiamo usare l'API Broadcast Channel per
riutilizzalo! Senza l'API Broadcast Channel, dovresti eseguire il loop sui risultati di self.clients.matchAll()
e chiamare postMessage()
su ciascun client per ottenere la comunicazione da un service worker a tutti i suoi client (codice effettivo che esegue questa operazione). L'utilizzo di un canale di trasmissione genera questo O(1)
anziché O(N)
.
Esempio: indica a un service worker di rimuovere una cache, riutilizzando i suoi metodi di utilità interna.
Nel file index.html
const channel = new BroadcastChannel('app-channel');
channel.onmessage = function(e) {
if (e.data.action === 'clearcache') {
console.log('Cache removed:', e.data.removed);
}
};
const messageChannel = new MessageChannel();
// Send the service worker a message to clear the cache.
// We can't use a BroadcastChannel for this because the
// service worker may need to be woken up. MessageChannels do that.
navigator.serviceWorker.controller.postMessage({
action: 'clearcache',
cacheName: 'v1-cache'
}, [messageChannel.port2]);
In sw.js
function nukeCache(cacheName) {
return caches.delete(cacheName).then(removed => {
// ...do more stuff (internal) to this service worker...
return removed;
});
}
self.onmessage = function(e) {
const action = e.data.action;
const cacheName = e.data.cacheName;
if (action === 'clearcache') {
nukeCache(cacheName).then(removed => {
// Send the main page a response via the BroadcastChannel API.
// We could also use e.ports[0].postMessage(), but the benefit
// of responding with the BroadcastChannel API is that other
// subscribers may be listening.
const channel = new BroadcastChannel('app-channel');
channel.postMessage({action, removed});
});
}
};
Differenza con postMessage()
A differenza di postMessage()
, non è più necessario gestire un riferimento a un iframe o a un worker per poter comunicare con quell'iframe:
// Don't have to save references to window objects.
const popup = window.open('https://another-origin.com', ...);
popup.postMessage('Sup popup!', 'https://another-origin.com');
window.postMessage()
ti consente anche di comunicare tra origini. L'API Broadcast Channel ha la stessa origine. Poiché è garantito che i messaggi provengano dalla stessa origine, non è necessario convalidarli come facevamo prima con window.postMessage()
:
// Don't have to validate the origin of a message.
const iframe = document.querySelector('iframe');
iframe.contentWindow.onmessage = function(e) {
if (e.origin !== 'https://expected-origin.com') {
return;
}
e.source.postMessage('Ack!', e.origin);
};
Basta "Iscriviti" a un determinato canale e garantire una comunicazione sicura e bidirezionale.
Differenza con SharedWorkers
Utilizza BroadcastChannel
per i casi semplici in cui devi inviare un messaggio a diverse finestre/schede o a diversi worker.
Per casi d'uso più elaborati, come la gestione dei blocchi, dello stato condiviso, la sincronizzazione delle risorse tra un server e più client o la condivisione di una connessione WebSocket con un host remoto, i worker condivisi sono la soluzione più appropriata.
Differenza con l'API MessageChannel
La differenza principale tra l'API Channel Messaging e BroadcastChannel
è che quest'ultima è un mezzo per inviare messaggi a più listener (one-to-many). MessageChannel
è pensato per la comunicazione one-to-one diretta tra gli script. Inoltre, richiede di configurare canali con una porta su entrambe le estremità.
Rilevamento delle funzionalità e supporto del browser
Attualmente, Chrome 54, Firefox 38 e Opera 41 supportano l'API Broadcast Channel.
if ('BroadcastChannel' in self) {
// BroadcastChannel API supported!
}
Per quanto riguarda i polyfill, ce ne sono alcuni:
- https://gist.github.com/alexis89x/041a8e20a9193f3c47fb
- https://gist.github.com/inexorabletash/52f437d1451d12145264
Non ho provato questi suggerimenti, quindi il chilometraggio potrebbe variare.