BroadcastChannel API - عبارة عن ناقل رسائل للويب

إريك بيدلمان

تسمح BroadcastChannel API للنصوص البرمجية من المصدر نفسه بإرسال رسائل إلى سياقات تصفُّح أخرى. يمكن اعتبارها ناقل رسائل بسيط يسمح بدلالات pub/sub بين النوافذ/علامات التبويب وإطارات iframe وعاملي الويب وعاملي الخدمات.

أساسيات واجهة برمجة التطبيقات

Broadcast Channel API هي واجهة برمجة تطبيقات بسيطة تسهّل التواصل بين سياقات التصفح. أي، الاتصال بين النوافذ/علامات التبويب وإطارات iframe وعاملي الويب وعاملي الخدمات. يصل جميع المستمعين إلى هذه القناة إلى جميع المستمعين إلى الرسائل التي يتم نشرها على قناة معيّنة.

تستخدم الدالة الإنشائية BroadcastChannel معلَمة واحدة، وهي اسم القناة. يحدد الاسم القناة كما يظهر في سياقات التصفح.

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

إرسال الرسائل

ويمكن أن تكون الرسائل سلاسل أو أي عناصر متوافقة مع خوارزمية النسخ الاحتياطي المنظَّم (السلاسل والعناصر والمصفوفات والنقاط المركزية ومصفوفة المصفوفات والخريطة).

مثال - إرسال كائن تخزين البيانات الثنائية الكبيرة أو الملف

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

لن يتم بث القناة إلى نفسها. مثلاً، إذا كان لديك مستمع onmessage على الصفحة نفسها مع postMessage() للقناة نفسها، لا يتم تنشيط حدث message هذا.

الاختلافات مع الأساليب الأخرى

في هذه المرحلة، قد تتساءل عن علاقة ذلك بالأساليب الأخرى لنقل الرسائل مثل WebSockets وSharedWorkers وواجهة برمجة تطبيقات MessageChannel وwindow.postMessage(). لا تحل واجهة برمجة تطبيقات قناة البث محل واجهات برمجة التطبيقات هذه. كل منها يخدم غرضًا. تم تصميم Broadcast Channel API لتسهيل إجراء اتصال واحد بين متعددين بين النصوص البرمجية والمستندة إلى المصدر نفسه.

بعض حالات الاستخدام لقنوات البث:

  • رصد إجراءات المستخدمين في علامات التبويب الأخرى
  • معرفة ما إذا كان المستخدم يسجّل الدخول إلى الحساب في نافذة أو علامة تبويب أخرى
  • توجيه عامل لتنفيذ بعض الأعمال في الخلفية
  • معرفة وقت اكتمال الخدمة من خلال تنفيذ إجراء ما.
  • عندما يحمّل المستخدم صورة في نافذة واحدة، مرِّرها إلى الصفحات الأخرى المفتوحة.

مثال: صفحة تعرف متى يسجّل المستخدم خروجه حتى من علامة تبويب مفتوحة أخرى على الموقع الإلكتروني نفسه:

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

في مثال آخر، لنفترض أنّك أردت توجيه عامل خدمات لإزالة المحتوى المخزَّن مؤقتًا بعد أن يغيّر المستخدم "إعداد التخزين بلا اتصال بالإنترنت" في تطبيقك. يمكنك حذف ذاكرات التخزين المؤقت باستخدام window.caches، لكن قد يكون لدى عامل الخدمة أداة مساعدة لإجراء ذلك. يمكننا استخدام Broadcast Channel API لإعادة استخدام هذا الرمز! بدون واجهة Broadcast Channel API، سيكون عليك تكرار نتائج self.clients.matchAll() واستدعاء postMessage() في كل عميل من أجل توصيل الاتصال من عامل خدمات إلى جميع عملائه (الرمز البرمجي الفعلي لإجراء ذلك). يؤدي استخدام قناة بث إلى إنشاء O(1) بدلاً من O(N).

مثال: توجيه طلب إلى عامل خدمات بإزالة ذاكرة تخزين مؤقت، وإعادة استخدام طرق الخدمات الداخلية الخاصة به.

في 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]);

في 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});
    });
    }
};

الفارق مع postMessage()

وعلى عكس postMessage()، لم تعُد مضطرًا للاحتفاظ بمرجع إلى إطار iframe أو عامل من أجل التواصل معه:

// 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() أيضًا التواصل من مصادر مختلفة. مصدر Broadcast Channel API هو نفسه. بما أنّ الرسائل واردة من المصدر نفسه مضمونها، لا تحتاج إلى التحقّق من صحتها كما اعتدنا في استخدام 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);
};

ما عليك سوى "الاشتراك" في قناة معيّنة والتمتع باتصال آمن وثنائي الاتجاه.

الفرق مع SharedWorkers

يمكنك استخدام "BroadcastChannel" للحالات البسيطة التي تحتاج فيها إلى إرسال رسالة إلى عدة نوافذ أو علامات تبويب أو عوامل محتمَلة.

بالنسبة إلى حالات الاستخدام الأكثر روعة مثل إدارة الأقفال، أو الحالة المشتركة، أو مزامنة الموارد بين الخادم وعدة عملاء، أو مشاركة اتصال WebSocket مع مضيف بعيد، فإن العاملين المشتركين هم الحل الأنسب.

الفرق مع واجهة برمجة التطبيقات MessageChannel API

يكمن الفرق الرئيسي بين Channel Messaging API وBroadcastChannel في أنّ الأخيرة هي وسيلة لإرسال الرسائل إلى مستمعين متعددين (مستمع واحد إلى متعدد). MessageChannel مخصّصة للتواصل بين شخصَين مباشرةً بين النصوص البرمجية. وهي أيضًا أكثر استخدامًا من غيرها، ما يتطلّب منك إعداد قنوات باستخدام منفذ على كل طرف.

اكتشاف الميزات ودعم المتصفِّح

في الوقت الحالي، يدعم Chrome 54 وFirefox 38 وOpera 41 واجهة برمجة تطبيقات قناة البث.

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

بالنسبة إلى رموز Polyfill البرمجية، هناك عدد قليل منها:

لم أجرّب ذلك، لذا قد تختلف المسافة المقطوعة.

المراجِع