تسمح واجهة برمجة التطبيقات BroadcastChannel API للنصوص البرمجية من المصدر نفسه بإرسال الرسائل إلى سياقات تصفّح أخرى. ويمكن اعتباره حافلة رسائل بسيطة تسمح بدلالات النشر/الاشتراك بين النوافذ/علامات التبويب وأُطر iframe وWeb Workers ومشغّلي الخدمات.
أساسيات واجهة برمجة التطبيقات
Broadcast Channel API هي واجهة برمجة تطبيقات بسيطة تسهّل التواصل بين سياقات التصفح. أي التواصل بين النوافذ/علامات التبويب وأُطر iframe وWeb Workers ومشغّلي الخدمات. يتم إرسال الرسائل المنشورة على قناة معيّنة إلى جميع مستمعي تلك القناة.
تستخدم الدالة الإنشائية 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();
إرسال الرسائل
يمكن أن تكون الرسائل سلاسل أو أي محتوى متوافق مع خوارزمية النسخ المماثل من الموقع (السلاسل والكائنات والمصفوفات وBlobs وArayBuffer والخريطة).
مثال - إرسال Blob أو ملف
channel.postMessage(new Blob(['foo', 'bar'], {type: 'plain/text'}));
لن تبث القناة المحتوى إلى نفسها. لذلك، إذا كان لديك مستمع onmessage
على الصفحة نفسها مع postMessage()
على القناة نفسها، لن يتم تنشيط حدث message
هذا.
الاختلافات مع الأساليب الأخرى
في هذه المرحلة، قد تتساءل عن كيفية ارتباط ذلك بأساليب أخرى لنقل الرسائل، مثل WebSockets وSharedWorkers وMessageChannel
API وwindow.postMessage()
. ولا تحلّ واجهة برمجة التطبيقات Broadcast Channel API محلّ هذه الواجهات. ولكل منها غرض. تم تصميم واجهة برمجة التطبيقات 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
للتواصل بين شخصَين مباشرةً بين النصوص. ويتطلب هذا الإجراء أيضًا المزيد من الخطوات، إذ عليك إعداد قنوات تتضمّن منفذًا في كل طرف.
رصد الميزات وتوافق المتصفّح
تتوفّر حاليًا واجهة برمجة التطبيقات Broadcast Channel API في الإصدار 54 من Chrome والإصدار 38 من Firefox والإصدار 41 من Opera.
if ('BroadcastChannel' in self) {
// BroadcastChannel API supported!
}
بالنسبة إلى polyfills، هناك بضعة polyfills:
- https://gist.github.com/alexis89x/041a8e20a9193f3c47fb
- https://gist.github.com/inexorabletash/52f437d1451d12145264
لم أُجرِ هذه الاختبارات، لذا قد تختلف المسافة التي تقطعها.