BroadcastChannel API - Bus pesan untuk web

BroadcastChannel API memungkinkan skrip dari origin yang sama untuk mengirim pesan ke konteks penjelajahan lainnya. Pub/Sub dapat dianggap sebagai bus pesan sederhana yang memungkinkan semantik pub/sub antara jendela/tab, iframe, pekerja web, dan pekerja layanan.

Dasar-dasar API

Broadcast Channel API adalah API sederhana yang memudahkan komunikasi antar-konteks penjelajahan. Artinya, berkomunikasi antara jendela/tab, iframe, pekerja web, dan pekerja layanan. Pesan yang diposting ke saluran tertentu akan dikirim ke semua pemroses saluran tersebut.

Konstruktor BroadcastChannel menggunakan satu parameter: nama saluran. Nama ini mengidentifikasi channel dan ditampilkan di seluruh konteks penjelajahan.

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

Mengirim pesan

Pesan dapat berupa string atau apa pun yang didukung oleh algoritma clone terstruktur (String, Objek, Array, Blob, ArrayBuffer, Peta).

Contoh - mengirim Blob atau File

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

Saluran tidak akan menyiarkan ke dirinya sendiri. Jadi, jika Anda memiliki pemroses onmessage di halaman yang sama dengan postMessage() ke saluran yang sama, peristiwa message tersebut tidak akan diaktifkan.

Perbedaan dengan teknik lain

Pada tahap ini, Anda mungkin ingin tahu apa kaitannya dengan teknik lain untuk penerusan pesan seperti WebSockets, SharedWorkers, MessageChannel API, dan window.postMessage(). Broadcast Channel API tidak menggantikan API ini. Masing-masing memiliki tujuan. Broadcast Channel API dimaksudkan untuk komunikasi one-to-many yang mudah antara skrip di origin yang sama.

Beberapa kasus penggunaan untuk saluran siaran:

  • Mendeteksi tindakan pengguna di tab lain
  • Mengetahui kapan pengguna login ke akun di jendela/tab lain.
  • Memberi petunjuk kepada pekerja untuk melakukan beberapa tugas latar belakang
  • Mengetahui kapan layanan selesai melakukan beberapa tindakan.
  • Saat pengguna mengupload foto di satu jendela, teruskan foto tersebut ke halaman terbuka lainnya.

Contoh - halaman yang mengetahui kapan pengguna logout, bahkan dari tab lain yang terbuka di situs yang sama:

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

Dalam contoh lain, misalkan Anda ingin menginstruksikan pekerja layanan untuk menghapus konten yang disimpan dalam cache setelah pengguna mengubah "setelan penyimpanan offline" di aplikasi Anda. Anda dapat menghapus cache tersebut menggunakan window.caches, tetapi pekerja layanan mungkin sudah berisi utilitas untuk melakukannya. Kita dapat menggunakan Broadcast Channel API untuk menggunakan kembali kode tersebut. Tanpa Broadcast Channel API, Anda harus melakukan loop pada hasil self.clients.matchAll() dan memanggil postMessage() di setiap klien untuk mencapai komunikasi dari pekerja layanan ke semua kliennya (kode sebenarnya yang melakukannya). Menggunakan Saluran Siaran menjadikan O(1) ini, bukan O(N).

Contoh - menginstruksikan pekerja layanan untuk menghapus cache, menggunakan kembali metode utilitas internalnya.

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

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

Perbedaan dengan postMessage()

Tidak seperti postMessage(), Anda tidak perlu lagi mempertahankan referensi ke iframe atau pekerja untuk berkomunikasi dengannya:

// 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() juga memungkinkan Anda berkomunikasi di seluruh origin. Broadcast Channel API memiliki origin yang sama. Karena pesan dijamin berasal dari asal yang sama, Anda tidak perlu memvalidasinya seperti yang biasa dilakukan dengan 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);
};

Cukup "subscribe" ke saluran tertentu dan lakukan komunikasi dua arah yang aman.

Perbedaan dengan SharedWorkers

Gunakan BroadcastChannel untuk kasus sederhana saat Anda perlu mengirim pesan ke beberapa jendela/tab, atau pekerja.

Untuk kasus penggunaan yang lebih canggih seperti mengelola kunci, status bersama, menyinkronkan resource antara server dan beberapa klien, atau berbagi koneksi WebSocket dengan host jarak jauh, pekerja bersama adalah solusi yang paling sesuai.

Perbedaan dengan MessageChannel API

Perbedaan utama antara Channel Messaging API dan BroadcastChannel adalah bahwa channel ini berfungsi untuk mengirim pesan ke beberapa pemroses (one-to-many). MessageChannel dimaksudkan untuk komunikasi one-to-one secara langsung antarskrip. Cara ini juga lebih rumit, mengharuskan Anda mengatur saluran dengan porta di setiap ujungnya.

Deteksi fitur dan dukungan browser

Saat ini, Chrome 54, Firefox 38, dan Opera 41 mendukung Broadcast Channel API.

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

Untuk polyfill, ada beberapa polyfill yang tersedia:

Saya belum mencobanya, jadi pengalaman Anda mungkin berbeda.

Resource