BroadcastChannel API - Bus pesan untuk web

BroadcastChannel API memungkinkan skrip dengan origin yang sama mengirim pesan ke konteks penjelajahan lainnya. Layanan ini bisa dianggap sebagai bus pesan sederhana yang memungkinkan semantik pub/sub antara jendela/tab, iframe, web worker, dan service worker.

Dasar-dasar API

Broadcast Channel API adalah API sederhana yang mempermudah komunikasi antar-konteks penjelajahan. Yaitu, berkomunikasi antara jendela/tab, iframe, web worker, dan service worker. Pesan yang diposting ke saluran tertentu akan dikirim ke semua pemroses saluran tersebut.

Konstruktor BroadcastChannel menggunakan satu parameter: nama saluran. Nama menunjukkan channel dan ditampilkan di berbagai 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, Map).

Contoh - mengirim Blob atau File

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

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

Perbedaan dengan teknik lain

Pada tahap ini, Anda mungkin ingin tahu bagaimana 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 ditujukan untuk komunikasi one-to-many yang mudah antara skrip pada asal yang sama.

Beberapa kasus penggunaan untuk saluran siaran:

  • Mendeteksi tindakan pengguna di tab lain
  • Mengetahui saat pengguna login ke akun di jendela/tab lain.
  • Instruksikan pekerja untuk melakukan beberapa pekerjaan di latar belakang
  • Mengetahui kapan layanan selesai melakukan beberapa tindakan.
  • Saat pengguna mengupload foto di satu jendela, berikan foto tersebut ke halaman lain yang terbuka.

Contoh - halaman yang mengetahui kapan pengguna logout, bahkan dari tab terbuka lain 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 yang lain, misalnya Anda ingin memerintahkan pekerja layanan untuk menghapus konten yang tersimpan dalam cache setelah pengguna mengubah "setelan penyimpanan offline" di aplikasi Anda. Anda dapat menghapus cache mereka menggunakan window.caches, tetapi pekerja layanan mungkin sudah berisi utilitas untuk melakukannya. Kita bisa menggunakan Broadcast Channel API untuk menggunakan kembali kode itu. Tanpa Broadcast Channel API, Anda harus melakukan loop atas hasil self.clients.matchAll() dan memanggil postMessage() pada setiap klien untuk melakukan komunikasi dari pekerja layanan ke semua kliennya (kode sebenarnya yang melakukannya). Menggunakan Saluran Siaran akan membuat O(1) ini, bukan O(N).

Contoh - minta pekerja layanan untuk menghapus cache, dengan 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 asal yang sama. Karena pesan dijamin berasal dari asal yang sama, Anda tidak perlu memvalidasinya seperti biasanya 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 "berlangganan" ke saluran tertentu dan miliki 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 mewah seperti mengelola kunci, status bersama, menyinkronkan sumber daya antara server dan banyak klien, atau berbagi koneksi WebSocket dengan host jarak jauh, pekerja bersama adalah solusi yang paling tepat.

Perbedaan dengan MessageChannel API

Perbedaan utama antara Channel Messaging API dan BroadcastChannel adalah bahwa API ini merupakan cara untuk mengirim pesan ke beberapa pemroses (one-to-many). MessageChannel dimaksudkan untuk komunikasi one-to-one langsung antara skrip. Proses ini juga lebih rumit, karena Anda harus menyiapkan saluran dengan porta di kedua 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!
}

Ada beberapa jenis polyfill di luar sana:

Saya belum mencobanya, jadi jarak tempuh Anda mungkin berbeda.

Referensi