تسمح واجهة برمجة التطبيقات 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();
إرسال الرسائل
يمكن أن تكون الرسائل سلاسل أو أي شيء يتوافق مع خوارزمية النسخة المهيكلة (سلاسل أو كائنات أو صفائف أو ملفات تعريفية أو ArrayBuffer أو 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 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
لم أُجرِ هذه الاختبارات، لذا قد تختلف المسافة التي تقطعها.