BroadcastChannel API - Een berichtenbus voor internet

Met de BroadcastChannel API kunnen scripts van dezelfde oorsprong berichten naar andere browsercontexten verzenden. Het kan worden gezien als een eenvoudige berichtenbus die pub/sub-semantiek tussen vensters/tabbladen, iframes, webwerkers en servicewerkers mogelijk maakt.

API-basisprincipes

De Broadcast Channel API is een eenvoudige API die de communicatie tussen browsercontexten eenvoudiger maakt. Dat wil zeggen, communicatie tussen vensters/tabbladen, iframes, webwerkers en servicemedewerkers. Berichten die op een bepaald kanaal worden geplaatst, worden afgeleverd bij alle luisteraars van dat kanaal.

De BroadcastChannel constructor gebruikt één enkele parameter: de naam van een kanaal. De naam identificeert het kanaal en leeft in verschillende browsercontexten.

// 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();

Berichten verzenden

Berichten kunnen strings zijn of iets anders dat wordt ondersteund door het gestructureerde kloonalgoritme (Strings, Objects, Arrays, Blobs, ArrayBuffer, Map).

Voorbeeld : een blob of bestand verzenden

channel.postMessage(new Blob(['foo', 'bar'], {type: 'plain/text'}));

Een zender zendt niet naar zichzelf uit. Dus als je een onmessage listener op dezelfde pagina hebt als een postMessage() op hetzelfde kanaal, wordt die message niet geactiveerd.

Verschillen met andere technieken

Op dit punt vraagt ​​u zich misschien af ​​hoe dit zich verhoudt tot andere technieken voor het doorgeven van berichten, zoals WebSockets, SharedWorkers, de MessageChannel API en window.postMessage() . De Broadcast Channel API vervangt deze API's niet. Elk dient een doel. De Broadcast Channel API is bedoeld voor eenvoudige één-op-veel-communicatie tussen scripts op dezelfde oorsprong .

Enkele gebruiksscenario's voor uitzendkanalen:

  • Detecteer gebruikersacties op andere tabbladen
  • Weet wanneer een gebruiker inlogt op een account in een ander venster/tabblad.
  • Geef een werknemer opdracht om wat achtergrondwerk uit te voeren
  • Weet wanneer een service klaar is en een actie uitvoert.
  • Wanneer de gebruiker een foto in één venster uploadt, kunt u deze doorgeven aan andere geopende pagina's.

Voorbeeld - pagina die weet wanneer de gebruiker uitlogt, zelfs vanaf een ander geopend tabblad op dezelfde 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>

In een ander voorbeeld stellen we dat u een servicemedewerker de opdracht wilt geven om in de cache opgeslagen inhoud te verwijderen nadat de gebruiker de 'offline opslaginstelling' in uw app heeft gewijzigd. U kunt hun caches verwijderen met window.caches , maar de servicemedewerker bevat mogelijk al een hulpprogramma om dit te doen. We kunnen de Broadcast Channel API gebruiken om die code opnieuw te gebruiken! Zonder de Broadcast Channel API zou u de resultaten van self.clients.matchAll() moeten herhalen en postMessage() op elke client moeten aanroepen om de communicatie van een servicemedewerker naar al zijn clients te bewerkstelligen ( daadwerkelijke code die doet dat ). Het gebruik van een uitzendkanaal maakt dit O(1) in plaats van O(N) .

Voorbeeld : instrueer een servicemedewerker om een ​​cache te verwijderen en de interne hulpprogrammamethoden opnieuw te gebruiken.

In 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});
    });
    }
};

Verschil met postMessage()

In tegenstelling tot postMessage() hoeft u niet langer een verwijzing naar een iframe of worker te onderhouden om ermee te kunnen communiceren:

// 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() kunt u ook over verschillende oorsprongen communiceren. De Broadcast Channel API is van dezelfde oorsprong . Omdat berichten gegarandeerd van dezelfde oorsprong komen, is het niet nodig om ze te valideren zoals we gewend zijn met 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);
};

"Abonneer" u eenvoudigweg op een bepaald kanaal en profiteer van veilige, bidirectionele communicatie!

Verschil met SharedWorkers

Gebruik BroadcastChannel voor eenvoudige gevallen waarin u een bericht naar mogelijk meerdere vensters/tabbladen of werknemers moet sturen.

Voor luxere gebruiksscenario's zoals het beheren van vergrendelingen, gedeelde status, het synchroniseren van bronnen tussen een server en meerdere clients, of het delen van een WebSocket-verbinding met een externe host, zijn gedeelde werkers de meest geschikte oplossing.

Verschil met MessageChannel API

Het belangrijkste verschil tussen de Channel Messaging API en BroadcastChannel is dat de laatste een manier is om berichten naar meerdere luisteraars te verzenden (één-op-veel). MessageChannel is bedoeld voor één-op-één communicatie rechtstreeks tussen scripts. Het is ook ingewikkelder, waardoor je kanalen met een poort aan elk uiteinde moet instellen.

Functiedetectie en browserondersteuning

Momenteel ondersteunen Chrome 54, Firefox 38 en Opera 41 de Broadcast Channel API.

if ('BroadcastChannel' in self) {
    // BroadcastChannel API supported!
}

Wat polyfills betreft, er zijn er een paar:

Ik heb deze niet geprobeerd, dus uw kilometerstand kan variëren.

Bronnen