BroadcastChannel API - Bus pesan untuk web

BroadcastChannel API memungkinkan skrip dari origin yang sama untuk mengirim pesan ke konteks penjelajahan lainnya. Fungsi ini 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 antara konteks penjelajahan. Artinya, berkomunikasi antara jendela/tab, iframe, pekerja web, dan pekerja layanan. Pesan yang diposting ke channel tertentu akan dikirimkan ke semua pendengar channel tersebut.

Konstruktor BroadcastChannel mengambil satu parameter: nama saluran. Nama ini mengidentifikasi saluran dan ditayangkan 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 algoritme clone terstruktur (String, Object, Array, Blob, ArrayBuffer, Map).

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

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 pada asal yang sama.

Beberapa kasus penggunaan untuk saluran siaran:

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

Contoh - halaman yang mengetahui saat 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, katakanlah Anda ingin menginstruksikan pekerja layanan untuk menghapus konten yang di-cache setelah pengguna mengubah "setelan penyimpanan offline" dalam aplikasi Anda. Anda dapat menghapus cache-nya menggunakan window.caches, tetapi pekerja layanan mungkin sudah berisi utilitas untuk melakukan ini. Kita bisa menggunakan {i> Broadcast Channel API<i} untuk menggunakan kembali kode itu! Tanpa Broadcast Channel API, Anda harus melakukan loop atas hasil self.clients.matchAll() dan memanggil postMessage() di setiap klien untuk melakukan komunikasi dari pekerja layanan ke semua kliennya (kode sebenarnya yang melakukan hal tersebut). Menggunakan Saluran Siaran menjadikan O(1) ini, bukan O(N).

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

Dalam 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 worker agar dapat 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 adalah origin yang sama. Karena pesan dijamin berasal dari asal yang sama, 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 "subscribe" ke saluran tertentu dan melakukan 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 resource antara server dan beberapa 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 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!
}

Sedangkan untuk polyfill, ada beberapa di luar sana:

Saya belum mencobanya, jadi jarak tempuh Anda mungkin berbeda-beda.

Resource