L'API BroadcastChannel permet aux scripts d'origine identique d'envoyer des messages à d'autres contextes de navigation. Il peut être considéré comme un simple bus de messages qui permet d'appliquer 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 différents contextes de navigation. Autrement dit, il s'agit de la communication entre les fenêtres/onglets, les iFrames, les Web workers et les service workers. Les messages publiés sur un canal donné sont distribués à tous les auditeurs de ce canal.
Le constructeur BroadcastChannel
n'accepte qu'un seul paramètre: le nom d'un canal.
Le nom permet d'identifier la chaîne et se situe dans différents 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 autre élément compatible avec l'algorithme de clonage structuré (chaînes, objets, tableaux, Blobs, ArrayBuffer, Map).
Exemple : envoi d'un objet Blob ou File
channel.postMessage(new Blob(['foo', 'bar'], {type: 'plain/text'}));
Une chaîne ne diffuse aucune annonce vers elle-même. Ainsi, si vous avez un écouteur onmessage
sur la même page qu'un postMessage()
sur la même chaîne, 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 est lié à d'autres techniques de transmission de messages telles que WebSockets, SharedWorkers, l'API MessageChannel
et window.postMessage()
. L'API Broadcast Channel ne remplace pas ces API. Chacune sert un objectif. L'API Broadcast Channel est conçue pour faciliter la communication un à plusieurs entre des scripts ayant la même origine.
Voici quelques cas d'utilisation des chaînes de diffusion:
- Détecter les actions des utilisateurs dans d'autres onglets
- Sachez quand un utilisateur se connecte à un compte dans une autre fenêtre ou un autre onglet.
- Demander à un nœud de calcul d'effectuer des tâches en arrière-plan
- Sachez quand un service a terminé d'effectuer une action.
- Lorsque l'utilisateur importe une photo dans une fenêtre, transmettez-la sur d'autres pages ouvertes.
Exemple de page qui sait quand l'utilisateur se déconnecte, même à partir d'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>
Dans un autre exemple, imaginons que vous vouliez 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 avec window.caches
, mais le service worker peut
contiennent déjà un utilitaire pour le faire. Nous pouvons utiliser
l'API Broadcast Channel pour
réutiliser ce code. Sans l'API Broadcast Channel, il vous faudrait effectuer une boucle sur les résultats de self.clients.matchAll()
et appeler postMessage()
sur chaque client afin d'établir la communication entre un service worker et l'ensemble de ses clients (code réellement utilisé pour effectuer cette opération). L'utilisation d'un canal de diffusion rend cette O(1)
au lieu de O(N)
.
Exemple : Demandez à 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 gérer une référence à un iFrame ou à un worker pour communiquer avec lui:
// 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 différentes origines. L'API Broadcast Channel est de même origine. Étant donné que les messages proviennent 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);
};
"S'abonner" simplement vers un canal particulier et d'avoir une communication sécurisée et bidirectionnelle !
Différence avec SharedWorkers
Utilisez BroadcastChannel
pour les cas simples où vous devez envoyer un message à plusieurs fenêtres/onglets ou nœuds de calcul.
Pour les cas d'utilisation plus pointus, tels que la gestion de verrous, l'état partagé, la synchronisation de ressources entre un serveur et plusieurs clients ou le partage d'une connexion WebSocket avec un hôte distant, les nœuds de calcul 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 d'envoyer des messages à plusieurs écouteurs (un à plusieurs). MessageChannel
est destiné à une communication de type un à un, directement entre les scripts. Elle est également plus complexe, car elle vous oblige à configurer des canaux avec un port à chaque extrémité.
Détection de 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!
}
En ce qui concerne les polyfills, il en existe quelques-uns:
- https://gist.github.com/alexis89x/041a8e20a9193f3c47fb
- https://gist.github.com/inexorabletash/52f437d1451d12145264
Je n'ai pas essayé. Votre kilométrage peut donc varier.