في بعض الحالات، قد يحتاج تطبيق الويب إلى إنشاء قناة اتصال ثنائية بين ومشغّل الخدمات.
على سبيل المثال: في بودكاست PWA يمكن إنشاء ميزة تتيح للمستخدم تنزيل حلقات استهلاكه بلا اتصال بالإنترنت والسماح عامل الخدمة لإبقاء الصفحة على اطلاع دائم بالتقدم المحرز، لذا فإن الموضوع يمكنها تحديث واجهة المستخدم.
سوف نستكشف في هذا الدليل الطرق المختلفة لتنفيذ اتصال ثنائي الاتجاه بين خدمة النافذة و العامل، من خلال استكشاف لواجهات برمجة تطبيقات مختلفة، ومكتبة Workbox، بالإضافة إلى بعض الحالات المتقدمة.
استخدام Workbox
workbox-window
عبارة عن مجموعة من
وحدات مكتبة Workbox المخصّصة
أن يتم تشغيلها في سياق النافذة. يعمل Workbox
توفر طريقة messageSW()
لإرسال رسالة إلى مشغِّل الخدمات المسجَّل على المثيل
في انتظار رد.
ينشئ رمز الصفحة التالي مثيل Workbox
جديدًا ويرسل رسالة إلى مشغّل الخدمات.
للحصول على إصدارها:
const wb = new Workbox('/sw.js');
wb.register();
const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);
ينفذ عامل الخدمة أداة استماع للرسائل على الطرف الآخر، ويستجيب إلى المتحدث مشغّل الخدمات:
const SW_VERSION = '1.0.0';
self.addEventListener('message', (event) => {
if (event.data.type === 'GET_VERSION') {
event.ports[0].postMessage(SW_VERSION);
}
});
ضمن التفاصيل، تستخدم المكتبة واجهة برمجة تطبيقات خاصة بالمتصفّح سنراجعها في القسم التالي: رسالة قناة، ولكنها تجري الكثير من تفاصيل التنفيذ، ما يسهّل عملية الاستخدام مع الاستفادة من متصفّح واسع لواجهة برمجة التطبيقات هذه.
استخدام واجهات برمجة تطبيقات المتصفح
إذا لم تكن مكتبة Workbox كافية لتلبية احتياجاتك، تتوفر العديد من واجهات برمجة التطبيقات ذات المستوى الأدنى تنفيذ الاتصال "المتبادل" بين الصفحات ومشغّلي الخدمات. فيهما بعض أوجه التشابه والاختلافات:
أوجه التشابه:
- في جميع الحالات، يبدأ الاتصال من طرف واحد من خلال واجهة
postMessage()
ويتم تلقّيه على الجانب الآخر من خلال تنفيذ معالجmessage
. - من الناحية العملية، تسمح لنا جميع واجهات برمجة التطبيقات المتاحة بتنفيذ حالات الاستخدام نفسها، غير أنّ بعضها عملية التطوير في بعض السيناريوهات.
الاختلافات:
- لديهم طرق مختلفة لتحديد الجانب الآخر من الاتصال: يستخدم بعضهم إشارة صريحة إلى السياق الآخر، بينما يمكن للآخرين التواصل ضمنيًا عبر وكيل يتم إنشاء مثيل له على كل جانب.
- ويختلف توافق المتصفح من حيث لآخر.
واجهة برمجة تطبيقات قناة البث
Broadcast Channel API. تسمح بالاتصال الأساسي بين سياقات التصفح عبر BroadcastChannel .
لتنفيذ ذلك، يجب أولاً إنشاء مثيل لعنصر BroadcastChannel
برقم التعريف نفسه في كل سياق.
وإرسال الرسائل واستلامها منه:
const broadcast = new BroadcastChannel('channel-123');
يعرض عنصر BroadcastChannel واجهة "postMessage()
" لإرسال رسالة إلى أي جهاز استماع.
السياق:
//send message
broadcast.postMessage({ type: 'MSG_ID', });
يمكن لأي سياق في المتصفّح الاستماع إلى الرسائل باستخدام طريقة onmessage
في BroadcastChannel
.
الكائن:
//listen to messages
broadcast.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process message...
}
};
وكما هو موضح، لا توجد إشارة صريحة إلى سياق معين، لذلك لا توجد حاجة إلى الحصول على الإشارة أولاً إلى عامل الخدمة أو أي عميل معين.
العيب هو أنه في وقت كتابة هذا التقرير، يتوفر دعم واجهة برمجة التطبيقات من Chrome، وFirefox وEdge، ولكن المتصفحات الأخرى مثل Safari لا تتوافق معها حتى الآن.
واجهة برمجة تطبيقات العميل
تتيح لك Client API الحصول على
الإشارة إلى جميع عناصر WindowClient
التي تمثّل علامات التبويب النشطة التي يتحكّم فيها مشغّل الخدمات.
بما أن الصفحة يتحكم فيها عامل خدمة واحد، فإنه يستمع إلى ويرسل الرسائل إلى
مشغّل الخدمات النشط مباشرةً عبر واجهة serviceWorker
:
//send message
navigator.serviceWorker.controller.postMessage({
type: 'MSG_ID',
});
//listen to messages
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process response
}
};
وبالمثل، يستمع عامل الخدمة إلى الرسائل من خلال استخدام أداة استماع onmessage
:
//listen to messages
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//Process message
}
});
للاتصال بأي من عملائه مرة أخرى، يحصل عامل الخدمة على مجموعة من
WindowClient
عناصر عن طريق التنفيذ
طرق مثل
Clients.matchAll()
و
Clients.get()
ثم يمكنه
postMessage()
أي منها:
//Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
if (clients && clients.length) {
//Respond to last focused tab
clients[0].postMessage({type: 'MSG_ID'});
}
});
Client API
هو خيار جيد للتواصل بسهولة مع جميع علامات التبويب النشطة من مشغّل الخدمات.
بطريقة مباشرة نسبيًا. تتوافق واجهة برمجة التطبيقات مع جميع
في المتصفّح،
ولكن قد لا تكون كل طرقه متوفرة، لذا احرص على التحقق من دعم المتصفح قبل
وتنفيذه في موقعك.
قناة الرسائل
تتطلب قناة المراسلة تحديد وتمرير منفذ من سياق إلى آخر لإنشاء اتصال ثنائي .
لإعداد القناة، تنشئ الصفحة مثيلاً للعنصر MessageChannel
وتستخدمه
لإرسال منفذ إلى مشغّل الخدمات المسجَّل. تنفِّذ الصفحة أيضًا أداة استماع onmessage
على
تلقّي رسائل من السياق الآخر:
const messageChannel = new MessageChannel();
//Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
messageChannel.port2,
]);
//Listen to messages
messageChannel.port1.onmessage = (event) => {
// Process message
};
يتلقى عامل الخدمة المنفذ، ويحفظ مرجعًا له ويستخدمه لإرسال رسالة إلى الجهة الأخرى الجانب:
let communicationPort;
//Save reference to port
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'PORT_INITIALIZATION') {
communicationPort = event.ports[0];
}
});
//Send messages
communicationPort.postMessage({type: 'MSG_ID'});
MessageChannel
متوافقة حاليًا مع جميع
في المتصفّح.
واجهات برمجة التطبيقات المتقدمة: المزامنة في الخلفية والجلب في الخلفية
في هذا الدليل، استكشفنا طُرقًا لتنفيذ تقنيات التواصل الثنائي الاتجاه، حالات بسيطة، مثل تمرير رسالة سلسلة تصف العملية المطلوب تنفيذها، أو قائمة بعناوين URL التخزين المؤقت من سياق إلى آخر. سنستكشف في هذا القسم واجهتَي برمجة تطبيقات للتعامل مع وهي: نقص الاتصال والتنزيلات الطويلة.
المزامنة في الخلفية
قد يرغب أحد تطبيقات الدردشة في ضمان عدم فقدان الرسائل مطلقًا بسبب الاتصال السيئ. تشير رسالة الأشكال البيانية تتيح لك واجهة برمجة تطبيقات المزامنة في الخلفية تأجيل الإجراءات التي ستتم إعادة محاولة تنفيذها عندما يكون لدى المستخدم اتصال مستقر. يعد ذلك مفيدًا لضمان كل ما يريد المستخدم إرساله، يتم إرساله بالفعل.
بدلاً من الواجهة postMessage()
، تسجِّل الصفحة sync
:
navigator.serviceWorker.ready.then(function (swRegistration) {
return swRegistration.sync.register('myFirstSync');
});
بعد ذلك، يستمع عامل الخدمة إلى الحدث "sync
" لمعالجة الرسالة:
self.addEventListener('sync', function (event) {
if (event.tag == 'myFirstSync') {
event.waitUntil(doSomeStuff());
}
});
يجب أن تعرض الدالة doSomeStuff()
وعدًا يشير إلى نجاح أو فشل كل ما هو
تحاول فعله. وفي حال تنفيذ الإجراء، تكتمل المزامنة. إذا تعذَّر ذلك، ستتم جدولة عملية مزامنة أخرى
إعادة المحاولة. تؤدي إعادة محاولة المزامنة أيضًا إلى انتظار الاتصال، واستخدام رقود أسي.
وبعد إجراء العملية، يمكن لعامل الخدمة التواصل مرة أخرى مع الصفحة وتحديث واجهة المستخدم، باستخدام أي من واجهات برمجة التطبيقات للاتصال التي تم استكشافها سابقًا.
يستخدم محرّك بحث Google ميزة "مزامنة الخلفية" للحفاظ على طلبات البحث التي تعذّر تنفيذها بسبب ضعف الاتصال، ثم إعادة المحاولة لاحقًا عندما يكون المستخدم متصلاً بالإنترنت. وبمجرد إجراء العملية، تقوم بإبلاغ النتيجة إلى المستخدم عبر إشعار فوري على الويب:
استرجاع في الخلفية
بالنسبة إلى المهام القصيرة نسبيًا مثل إرسال رسالة أو قائمة عناوين URL للتخزين المؤقت، قد تكون الخيارات استكشافها حتى الآن اختيارًا جيدًا. إذا استغرقت المهمة وقتًا طويلاً جدًا، سيوقف المتصفح الخدمة. عامل، وإلا يشكل خطرًا على خصوصية المستخدم وبطاريته.
واجهة برمجة التطبيقات لجلب الخلفية تسمح لك بتفريغ مهمة طويلة إلى عامل الخدمة، مثل تنزيل الأفلام أو ملفات البودكاست أو المستويات للعبة.
للتواصل مع مشغّل الخدمات من الصفحة، استخدِم backgroundFetch.fetch
بدلاً من
postMessage()
:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.fetch(
'my-fetch',
['/ep-5.mp3', 'ep-5-artwork.jpg'],
{
title: 'Episode 5: Interesting things.',
icons: [
{
sizes: '300x300',
src: '/ep-5-icon.png',
type: 'image/png',
},
],
downloadTotal: 60 * 1024 * 1024,
},
);
});
يسمح كائن BackgroundFetchRegistration
للصفحة بالاستماع إلى الحدث progress
للمتابعة.
مدى تقدم التنزيل:
bgFetch.addEventListener('progress', () => {
// If we didn't provide a total, we can't provide a %.
if (!bgFetch.downloadTotal) return;
const percent = Math.round(
(bgFetch.downloaded / bgFetch.downloadTotal) * 100,
);
console.log(`Download progress: ${percent}%`);
});
الخطوات التالية
تعرّفنا في هذا الدليل على الحالة الأكثر شيوعًا للتواصل بين مشغّلي الصفحات وعاملي الخدمات. (الاتصال ثنائي الاتجاه).
في كثير من الأحيان، قد يحتاج المرء إلى سياق واحد فقط للتواصل مع الآخر، دون تلقي الاستجابة. اطلع على الأدلة التالية للحصول على إرشادات حول كيفية تنفيذ تقنيات أحادي الاتجاه في صفحاتك من مشغّل الخدمات وإليها، بالإضافة إلى حالات الاستخدام وأمثلة على الإنتاج:
- دليل التخزين المؤقت الضمني: الاتصال بمشغّل الخدمات من الصفحة ذاكرة التخزين المؤقت مقدمًا (على سبيل المثال، في سيناريوهات الجلب المسبق).
- تحديثات البث: الاتصال بالصفحة من عامل الخدمة لإبلاغه بالصفحة عن التحديثات المهمة (على سبيل المثال، يتوفر إصدار جديد من تطبيق الويب).