Interfejs BroadcastChannel API umożliwia skryptom tej samej domeny wysyłanie wiadomości do innych kontekstów przeglądania. Można ją traktować jako prostą magistralę wiadomości, która umożliwia semantykę pub/Sub między oknami/kartami, elementami iframe, instancjami internetowymi oraz mechanizmami Service Worker.
Podstawowe informacje o interfejsie API
Broadcast Channel API to prosty interfejs API, który ułatwia komunikację między kontekstami przeglądania. Oznacza to komunikację między oknami/kartami, elementami iframe, instancjami internetowymi oraz mechanizmami Service Worker. Wiadomości publikowane na danym kanale trafiają do wszystkich jego słuchaczy.
Konstruktor BroadcastChannel
przyjmuje pojedynczy parametr: nazwę kanału.
Nazwa identyfikuje kanał i odnosi się do wszystkich kontekstów przeglądania.
// 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();
Wysyłanie wiadomości
Wiadomości mogą być ciągami tekstowymi lub dowolnymi elementami obsługiwanymi przez algorytm klonu strukturalnego (ciągi znaków, obiekty, tablice, obiekty blob, tablicaBuffer czy mapa).
Przykład – wysyłanie obiektu blob lub pliku
channel.postMessage(new Blob(['foo', 'bar'], {type: 'plain/text'}));
Kanał nie będzie transmitować do siebie samego. Jeśli masz słuchacz onmessage
na tej samej stronie co postMessage()
do tego samego kanału, to zdarzenie message
nie włącza się.
Różnice w porównaniu z innymi technikami
Być może zastanawiasz się, jak wiąże się to z innymi technikami przekazywania wiadomości, takimi jak WebSockets, SharedWorkers, MessageChannel
API i window.postMessage()
. Interfejs Broadcast Channel API nie zastępuje tych interfejsów. Każdy z nich ma jakiś cel. Interfejs Broadcast Channel API służy do łatwej komunikacji jeden do wielu między skryptami w tym samym źródle.
Oto kilka przypadków użycia kanałów naziemnych:
- Wykrywanie działań użytkowników na innych kartach
- Otrzymuj powiadomienia, gdy użytkownik loguje się na konto w innym oknie lub na innej karcie.
- Instruowanie pracownika, aby wykonał pracę w tle
- Wiedz, kiedy usługa wykonuje działanie.
- Gdy użytkownik przesyła zdjęcie w jednym oknie, przekaż je na inne otwarte strony.
Przykład – strona, która wie, kiedy użytkownik się wylogowuje, nawet z innej otwartej karty w tej samej witrynie:
<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>
W innym przykładzie załóżmy, że chcesz poprosić skrypt service worker o usunięcie
zawartość pamięci podręcznej po zmianie „ustawień przechowywania offline” przez użytkownika w aplikacji.
Możesz usunąć ich pamięci podręczne za pomocą window.caches
, ale skrypt service worker może
zawiera już narzędzie do wykonywania tej czynności. Możemy użyć interfejsu Broadcast Channel API do
użyj ponownie tego kodu. Bez interfejsu Broadcast Channel API należałoby zapętlić wyniki funkcji self.clients.matchAll()
i wywołać postMessage()
w przypadku każdego klienta, aby zapewnić komunikację między mechanizmem Service Worker a wszystkimi klientami (rzeczywisty kod, który to umożliwia). Jeśli używasz kanału transmisji, to O(1)
zamiast O(N)
.
Przykład: poproś skrypt service worker o usunięcie pamięci podręcznej z zastosowaniem wewnętrznych metod narzędzia.
W 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]);
W 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});
});
}
};
Różnica w stosunku do postMessage()
W przeciwieństwie do postMessage()
nie musisz już utrzymywać odniesienia do elementu iframe ani instancji roboczej, aby się z nim komunikować:
// 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()
umożliwia też komunikację między źródłami. Interfejs Broadcast Channel API pochodzi z tej samej domeny. Wiadomości gwarantują, że będą pochodzić z tego samego źródła, więc nie trzeba weryfikować ich tak jak to było wcześniej w usłudze 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);
};
Po prostu „zasubskrybuj” z konkretnym kanałem i zapewnić bezpieczną, dwukierunkową komunikację.
Różnica względem obiektów SharedWorkers
BroadcastChannel
używaj w prostych przypadkach, gdy musisz wysłać wiadomość do potencjalnie kilku okien/kart lub do instancji roboczych.
W bardziej złożonych przypadkach, takich jak zarządzanie blokadami, udostępnianie stanu, synchronizowanie zasobów między serwerem a wieloma klientami czy udostępnianie połączenia WebSocket z hostem zdalnym, współużytkowane procesy robocze są najlepszym rozwiązaniem.
Różnica w stosunku do interfejsu MessageChannel API
Główna różnica między interfejsem Channel Messaging API a BroadcastChannel
polega na tym, że ten drugi sposób służy do wysyłania wiadomości do wielu detektorów (jeden do wielu). MessageChannel
służy do komunikacji jeden do jednego bezpośrednio między skryptami. Jest to również bardziej pracochłonne, ponieważ musisz skonfigurować kanały z portem z obu stron.
Wykrywanie funkcji i obsługa przeglądarki
Obecnie interfejs Broadcast Channel API obsługują przeglądarki Chrome 54, Firefox 38 i Opera 41.
if ('BroadcastChannel' in self) {
// BroadcastChannel API supported!
}
Jest ich kilka:
- https://gist.github.com/alexis89x/041a8e20a9193f3c47fb
- https://gist.github.com/inexorabletash/52f437d1451d12145264
Nie wypróbowałem(am) tych opcji, więc Twój dystans może być różny.