L'API BroadcastChannel permet aux scripts de même origine d'envoyer des messages à d'autres contextes de navigation. Il peut être considéré comme un simple bus de messagerie qui permet une sémantique pub/sub entre les fenêtres/onglets, les iFrames, les Web Workers et les service workers.
Principes de base des API
L'API Broadcast Channel est une API simple qui facilite la communication entre les contextes de navigation. C'est-à-dire la communication entre les fenêtres/onglets, les iFrames, les Web Workers et les services workers. Les messages publiés sur une chaîne donnée sont distribués à tous les auditeurs de cette chaîne.
Le constructeur BroadcastChannel
n'accepte qu'un seul paramètre: le nom d'un canal.
Le nom identifie la chaîne et est utilisé dans tous les contextes de navigation.
// 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();
Envoyer des messages
Les messages peuvent être des chaînes ou tout élément compatible avec l'algorithme de clone structuré (chaînes, objets, tableaux, objets blob, ArrayBuffer, Map).
Exemple : envoyer un blob ou un fichier
channel.postMessage(new Blob(['foo', 'bar'], {type: 'plain/text'}));
Une chaîne ne peut pas diffuser de contenu sur elle-même. Par conséquent, si vous disposez d'un écouteur onmessage
sur la même page qu'un postMessage()
sur le même canal, cet événement message
ne se déclenche pas.
Différences avec d'autres techniques
À ce stade, vous vous demandez peut-être en quoi cela se rapporte à d'autres techniques de transmission de messages, comme WebSockets, SharedWorkers, l'API MessageChannel
et window.postMessage()
. L'API Broadcast Channel ne remplace pas ces API. Chacun a une fonction spécifique. L'API Broadcast Channel est conçue pour faciliter la communication de type "un à plusieurs" entre les scripts de la même origine.
Voici quelques cas d'utilisation des canaux de diffusion:
- Détecter les actions des utilisateurs dans d'autres onglets
- Savoir quand un utilisateur se connecte à un compte dans une autre fenêtre/un autre onglet
- Demander à un worker d'effectuer une tâche en arrière-plan
- Savoir quand un service a terminé une action
- Lorsque l'utilisateur importe une photo dans une fenêtre, faites-la passer aux autres pages ouvertes.
Exemple : page qui sait quand l'utilisateur se déconnecte, même depuis un autre onglet ouvert sur le même site :
<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>
Prenons un autre exemple. Imaginons que vous souhaitiez demander à un service worker de supprimer le contenu mis en cache une fois que l'utilisateur a modifié son "paramètre de stockage hors connexion" dans votre application. Vous pouvez supprimer ses caches à l'aide de window.caches
, mais le service worker peut déjà contenir un utilitaire pour ce faire. Nous pouvons utiliser l'API Broadcast Channel pour réutiliser ce code. Sans l'API Broadcast Channel, vous devriez effectuer une boucle sur les résultats de self.clients.matchAll()
et appeler postMessage()
sur chaque client pour assurer la communication d'un service worker avec tous ses clients (code réel qui fait cela). L'utilisation d'un canal de diffusion génère O(1)
au lieu de O(N)
.
Exemple : demander à un service worker de supprimer un cache en réutilisant ses méthodes utilitaires internes.
Dans 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]);
Dans 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});
});
}
};
Différence avec postMessage()
Contrairement à postMessage()
, vous n'avez plus besoin de conserver une référence à un iframe ou à un nœud de calcul pour communiquer avec eux:
// 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()
vous permet également de communiquer entre les origines. L'API Broadcast Channel est de même origine. Étant donné que les messages proviennent toujours de la même origine, il n'est pas nécessaire de les valider comme nous le faisions avec 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);
};
Il vous suffit de vous "abonner" à un canal spécifique pour bénéficier d'une communication bidirectionnelle et sécurisée.
Différence avec les SharedWorkers
Utilisez BroadcastChannel
dans les cas simples où vous devez envoyer un message à plusieurs fenêtres/onglets ou nœuds de calcul.
Pour les cas d'utilisation plus sophistiqués, tels que la gestion des verrous, l'état partagé, la synchronisation des ressources entre un serveur et plusieurs clients ou le partage d'une connexion WebSocket avec un hôte distant, les workers partagés sont la solution la plus appropriée.
Différence avec l'API MessageChannel
La principale différence entre l'API Channel Messaging et BroadcastChannel
est que cette dernière permet de distribuer des messages à plusieurs écouteurs (un à plusieurs). MessageChannel
est destiné à la communication directe entre scripts. Elle est également plus complexe, car vous devez configurer des canaux avec un port à chaque extrémité.
Détection des fonctionnalités et compatibilité avec les navigateurs
Actuellement, Chrome 54, Firefox 38 et Opera 41 sont compatibles avec l'API Broadcast Channel.
if ('BroadcastChannel' in self) {
// BroadcastChannel API supported!
}
Il existe plusieurs polyfills:
- https://gist.github.com/alexis89x/041a8e20a9193f3c47fb
- https://gist.github.com/inexorabletash/52f437d1451d12145264
Je ne les ai pas essayés, donc les résultats peuvent varier.