BroadcastChannel API — шина сообщений для Интернета.

API BroadcastChannel позволяет сценариям того же источника отправлять сообщения в другие контексты просмотра. Его можно рассматривать как простую шину сообщений, которая обеспечивает семантику публикации/подписки между окнами/вкладками, iframe, веб-работниками и сервис-воркерами.

Основы API

API широковещательного канала — это простой API, который упрощает взаимодействие между контекстами просмотра. То есть взаимодействие между окнами/вкладками, iframe, веб-работниками и сервис-воркерами. Сообщения, отправленные на определенный канал, доставляются всем слушателям этого канала.

Конструктор BroadcastChannel принимает единственный параметр: имя канала. Имя идентифицирует канал и действует в разных контекстах просмотра.

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

Отправка сообщений

Сообщения могут быть строками или чем-то еще, поддерживаемым алгоритмом структурированного клонирования (строки, объекты, массивы, большие двоичные объекты, ArrayBuffer, Map).

Пример — отправка Blob или файла

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

Канал не будет вещать сам на себя. Поэтому, если у вас есть прослушиватель onmessage на той же странице, что и postMessage() на том же канале, это событие message не срабатывает.

Отличия от других техник

На этом этапе вам может быть интересно, как это связано с другими методами передачи сообщений, такими как WebSockets, SharedWorkers, API MessageChannel и window.postMessage() . API широковещательного канала не заменяет эти API. Каждый служит определенной цели. API широковещательного канала предназначен для упрощения связи «один ко многим» между скриптами в одном источнике .

Некоторые варианты использования вещательных каналов:

  • Обнаружение действий пользователя на других вкладках
  • Знайте, когда пользователь входит в учетную запись в другом окне/вкладке.
  • Поручите работнику выполнить некоторую фоновую работу
  • Знайте, когда служба завершает выполнение какого-либо действия.
  • Когда пользователь загружает фотографию в одно окно, передайте ее на другие открытые страницы.

Пример — страница, которая знает, когда пользователь выходит из системы, даже из другой открытой вкладки на том же сайте:

<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>

В другом примере предположим, что вы хотите поручить сервисному работнику удалить кэшированный контент после того, как пользователь изменит свои «настройки автономного хранилища» в вашем приложении. Вы можете удалить их кеши с помощью window.caches , но сервис-воркер уже может содержать утилиту для этого. Мы можем использовать API широковещательного канала для повторного использования этого кода! Без API широковещательного канала вам пришлось бы перебирать результаты self.clients.matchAll() и вызывать postMessage() на каждом клиенте, чтобы обеспечить связь от сервисного работника со всеми его клиентами ( фактический код, который делает это ). Использование широковещательного канала делает это O(1) вместо O(N) .

Пример — поручить сервисному работнику удалить кеш, повторно используя его внутренние служебные методы.

В 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]);

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

Разница с postMessage()

В отличие от postMessage() , вам больше не нужно поддерживать ссылку на iframe или worker для связи с ним:

// 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() также позволяет вам общаться между источниками. API широковещательного канала имеет одно происхождение . Поскольку сообщения гарантированно приходят из одного и того же источника, нет необходимости проверять их, как мы делали это с помощью 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);
};

Просто «подпишитесь» на определенный канал и получите безопасную двустороннюю связь!

Разница с SharedWorkers

Используйте BroadcastChannel для простых случаев, когда вам нужно отправить сообщение потенциально нескольким окнам/вкладкам или работникам.

Для более интересных случаев использования, таких как управление блокировками, общее состояние, синхронизация ресурсов между сервером и несколькими клиентами или совместное использование соединения WebSocket с удаленным хостом, наиболее подходящим решением являются общие рабочие процессы.

Разница с API MessageChannel

Основное различие между API Channel Messaging и BroadcastChannel заключается в том, что последний является средством отправки сообщений множеству прослушивателей (один ко многим). MessageChannel предназначен для индивидуальной связи напрямую между скриптами. Это также более сложный процесс, требующий настройки каналов с портом на каждом конце.

Обнаружение функций и поддержка браузера

В настоящее время Chrome 54, Firefox 38 и Opera 41 поддерживают API широковещательного канала.

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

Что касается полифилов, то их несколько:

Я их не пробовал, поэтому ваши впечатления могут отличаться.

Ресурсы