BroadcastChannel API - Web için bir mesaj yolu

BroadcastChannel API, aynı kaynaktan komut dosyalarının diğer tarama bağlamlarına mesaj göndermesine olanak tanır. Pencereler/sekmeler, iframe'ler, web çalışanları ve hizmet çalışanları arasında yayın/abone semantiği sağlayan basit bir mesaj arabirimi olarak düşünülebilir.

API temel bilgileri

Yayın Kanalı API'si, tarama bağlamları arasında iletişimi kolaylaştıran basit bir API'dir. Yani pencereler/sekmeler, iframe'ler, web çalışanları ve hizmet çalışanları arasında iletişim kurulabilir. Belirli bir kanala gönderilen mesajlar, söz konusu kanalın tüm dinleyicilerine iletilir.

BroadcastChannel kurucusu tek bir parametre alır: kanalın adı. Ad, kanalı tanımlar ve tarama bağlamlarında kullanı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, dize veya yapılandırılmış kopya algoritması tarafından desteklenen herhangi bir şey (Dizeler, Nesneler, Diziler, Blob'lar, ArrayBuffer, Eşlem) olabilir.

Örnek: Blob veya dosya gönderme

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

Kanallar kendi yayınlarını kendileri izleyemez. Dolayısıyla, aynı kanaldaki postMessage() ile aynı sayfada bir onmessage dinleyiciniz varsa bu message etkinliği tetiklenmez.

Diğer tekniklerle arasındaki farklar

Bu noktada, bunun WebSocket'ler, SharedWorker'lar, MessageChannel API ve window.postMessage() gibi mesaj aktarma teknikleriyle nasıl bir ilişkisi olduğunu merak ediyor olabilirsiniz. Broadcast Channel API, bu API'lerin yerini almaz. Her birinin bir amacı vardır. Broadcast Channel API, aynı kaynaktaki komut dosyaları arasında kolay bir bire çok iletişim için tasarlanmıştır.

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

  • Diğer sekmelerdeki kullanıcı işlemlerini algılama
  • Kullanıcının başka bir pencerede/sekmede hesaba giriş yaptığını bilme
  • Bir çalışana arka planda çalışma yapması için talimat verme
  • Bir hizmetin bir işlemi ne zaman tamamladığını öğrenin.
  • Kullanıcı bir pencerede fotoğraf yüklediğinde, bu fotoğrafı diğer açık sayfalara aktarın.

Örnek: Kullanıcının oturumunu kapattığını (aynı sitedeki açık başka bir sekmeden bile) 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 örnekte, kullanıcı uygulamanızda "çevrimdışı depolama ayarını" değiştirdikten sonra bir hizmet çalışanına önbelleğe alınmış içeriği kaldırmasını talimat vermek istediğinizi varsayalım. window.caches kullanarak önbellekleri silebilirsiniz ancak hizmet çalışanı bunu yapacak bir yardımcı program içerebilir. Bu kodu yeniden kullanmak için Broadcast Channel API'yi kullanabiliriz. Yayın Kanalı API'si olmadan, bir hizmet çalışanının tüm istemcileriyle iletişim kurması için self.clients.matchAll() sonuçlarını döngü içinde incelemeniz ve her istemcide postMessage()'ı çağırmanız gerekir (bunu yapan gerçek kod). Yayın kanalı kullanıldığında bu değer O(N) yerine O(1) olur.

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

index.html dosyasında

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 dosyasında

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 farklar

postMessage()'ün aksine, artık bir iFrame veya işleyiciyle iletişim kurmak için ona referans vermeniz gerekmez:

// 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ı kaynaktan olmalıdır. İletilerin aynı kaynaktan geldiği garanti edildiğinden, window.postMessage() iletilerinde yaptığımız gibi bunları doğrulamamız gerekmez:

// 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" olarak güvenli ve iki yönlü iletişim kurabilirsiniz.

SharedWorkers ile arasındaki fark

Birden fazla pencereye/sekmeye veya çalışana mesaj göndermeniz gereken basit durumlarda BroadcastChannel değerini kullanın.

Kilitleri yönetme, paylaşılan durumu yönetme, kaynakları bir sunucu ile birden fazla 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 paylaşılan çalışanlar en uygun çözümdür.

MessageChannel API ile arasındaki fark

Channel Messaging API ile BroadcastChannel arasındaki temel fark, BroadcastChannel'nin birden fazla dinleyiciye (bire çok) mesaj gönderme aracı olmasıdır. MessageChannel, doğrudan komut dosyaları arasında bire bir iletişim için kullanılır. Ayrıca, her iki ucunda da bağlantı noktası bulunan kanallar oluşturmanızı gerektirdiğinden daha karmaşıktır.

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

Şu anda Chrome 54, Firefox 38 ve Opera 41, Yayın Kanalı API'sini desteklemektedir.

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

Polifill'ler söz konusu olduğunda birkaç seçenek vardır:

Bunları denemediğim için sonuç farklı olabilir.

Kaynaklar