تسمح 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();
إرسال الرسائل
يمكن أن تكون الرسائل سلاسل أو أي محتوى متوافق مع خوارزمية النسخ النصي المنظّم (السلاسل والكائنات والمصفوفات وBlobs وArayBuffer وMap).
مثال - إرسال 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
يتمثل الاختلاف الرئيسي بين Channel Messaging API وBroadcastChannel
في أنّ طريقة إرسال الرسائل إلى عدّة مستمعين (من واحد إلى متعدد). تم تصميم MessageChannel
للتواصل بين شخصَين مباشرةً بين النصوص. وهو يتطلّب أيضًا إعداد قنوات بمنفذ على كلّ منها.
رصد الميزات والتوافق مع المتصفحات
في الوقت الحالي، تتوافق الإصدارات Chrome 54 وFirefox 38 وOpera 41 مع واجهة برمجة تطبيقات البث للقناة.
if ('BroadcastChannel' in self) {
// BroadcastChannel API supported!
}
بالنسبة إلى رموز polyfill، هناك عدد قليل منها:
- https://gist.github.com/alexis89x/041a8e20a9193f3c47fb
- https://gist.github.com/inexorabletash/52f437d1451d12145264
لم أجرّب هذه الطرق، لذا قد تختلف المسافة المقطوعة.