BroadcastChannel API - Web için bir mesaj yolu

Eric Bidelman

BroadcastChannel API, aynı kaynak komut dosyalarının diğer tarama bağlamlarına mesaj göndermesine izin verir. Bu, pencereler/sekmeler, iframe'ler, web çalışanları ve hizmet çalışanları arasında pub/sub anlamlarına izin veren basit bir mesaj yolu olarak düşünülebilir.

API temel bilgileri

Broadcast Channel API'si, göz atma bağlamları arasında iletişim kurmayı kolaylaştıran basit bir API'dir. Yani pencereler/sekmeler, iframe'ler, web çalışanları ve hizmet çalışanları arasında iletişim kurulur. Belirli bir kanalda yayınlanan mesajlar, o kanalın tüm dinleyicilerine iletilir.

BroadcastChannel oluşturucu, tek bir parametre alır: kanalın adı. Ad, kanalı tanımlar ve farklı göz atma bağlamlarında barındırılır.

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

İleti gönderme

Mesajlar, dizeler veya yapılandırılmış klon algoritmasının (Dizeler, Nesneler, Diziler, Blob'lar, ArrayBuffer, Harita) desteklediği herhangi bir şey olabilir.

Örnek: Blob veya Dosya gönderme

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

Bir kanal kendi kendine yayın yapmaz. Dolayısıyla, aynı kanalda postMessage() ile aynı sayfada bir onmessage işleyiciniz varsa bu message etkinliği tetiklenmez.

Diğer tekniklerle olan farklar

Bu noktada, bunun WebSockets, SharedWorkers, MessageChannel API ve window.postMessage() gibi diğer ileti geçirme teknikleriyle nasıl bir bağlantısı olduğunu merak ediyor olabilirsiniz. Broadcast Channel API bu API'lerin yerini almaz. Bunların her biri bir amaca hizmet eder. Broadcast Channel API'si, aynı kaynaktaki komut dosyaları arasında bire-bire-çok iletişim kurulmasına yöneliktir.

Yayın kanallarıyla ilgili bazı kullanım alanları:

  • Diğer sekmelerdeki kullanıcı işlemlerini algıla
  • Kullanıcının başka bir pencerede/sekmede bir hesaba ne zaman giriş yaptığını öğrenin.
  • Bir çalışandan arka planda işlem yapmasını isteyin
  • Bir hizmetin belirli bir işlem tamamlanıp tamamlanmadığını öğrenme.
  • Kullanıcı bir pencerede bir fotoğraf yüklediğinde, fotoğrafı diğer açık sayfalara geçirin.

Örnek - kullanıcının aynı sitedeki başka bir açık sekmeden çıkış yaptığını bilen sayfa:

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

Başka bir örnek olarak, kullanıcı uygulamanızda "çevrimdışı depolama alanı ayarını" değiştirdikten sonra bir hizmet çalışanına önbelleğe alınan içeriği kaldırma talimatı vermek istediğinizi varsayalım. window.caches kullanarak önbelleklerini silebilirsiniz, ancak hizmet çalışanı bunu yapmak için halihazırda bir yardımcı program içerebilir. Broadcast Channel API'yi bu kodu yeniden kullanmak için kullanabiliriz. Broadcast Channel API olmasaydı bir hizmet çalışanının tüm müşterileriyle olan iletişimi (bunu yapan gerçek kod) gerçekleştirmek için self.clients.matchAll() sonuçlarını döngüye almanız ve her istemcide postMessage() yöntemini çağırmanız gerekirdi. Yayın Kanalı kullanıldığında O(N) yerine bu O(1) yapılır.

Örnek - Bir hizmet çalışanına, dahili yardımcı program yöntemlerini yeniden kullanarak bir önbelleği kaldırması yönünde talimat verin.

index.html içinde

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 içinde

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() ile arasındaki fark

postMessage()'den farklı olarak, bir iframe veya çalışanla iletişim kurmak için artık ona referans sağlamak zorunda değilsiniz:

// 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(), farklı kaynaklar arasında iletişim kurmanıza da olanak tanır. Broadcast Channel API aynı kaynaktır. İletilerin aynı kaynaktan alınacağı garanti edildiği için bunları window.postMessage() ile yaptığımız gibi doğrulamaya gerek yoktur:

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

Belirli bir kanala "abone olmanız" ve güvenli, iki yönlü iletişim kurmanız yeterli!

SharedWorkers ile arasındaki fark

Birden fazla pencereye/sekmeye veya çalışanlara ileti göndermeniz gereken basit durumlar için BroadcastChannel kullanın.

Kilitleri yönetme, paylaşılan durumu yönetme, kaynakları bir sunucu ve birden çok istemci arasında senkronize etme veya bir WebSocket bağlantısını uzak bir ana makineyle paylaşma gibi daha gelişmiş kullanım alanları için en uygun çözüm paylaşımlı çalışanlardır.

MessageChannel API ile fark

Channel Messaging API ile BroadcastChannel arasındaki temel fark, BroadcastChannel API'sinin mesajları birden çok dinleyiciye (bire-çok) göndermek için kullanılan bir yöntemdir. MessageChannel, doğrudan komut dosyaları arasında bire bir iletişim kurulmasına yöneliktir. Ayrıca daha karmaşıktır ve her iki ucunda bir bağlantı noktası bulunan kanallar oluşturmanız gerekir.

Özellik algılama ve tarayıcı desteği

Şu anda Chrome 54, Firefox 38 ve Opera 41, Broadcast Channel API'yi desteklemektedir.

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

Çoklu dolgu gibi birkaç seçenek mevcuttur:

Bunları denemedim, o yüzden kilometre değeri farklılık gösterebilir.

Kaynaklar