التواصل الثنائي مع عاملي الخدمة

في بعض الحالات، قد يحتاج تطبيق الويب إلى إنشاء قناة اتصال ثنائية بين ومشغّل الخدمات.

على سبيل المثال: في بودكاست 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.
  • من الناحية العملية، تسمح لنا جميع واجهات برمجة التطبيقات المتاحة بتنفيذ حالات الاستخدام نفسها، غير أنّ بعضها عملية التطوير في بعض السيناريوهات.

الاختلافات:

  • لديهم طرق مختلفة لتحديد الجانب الآخر من الاتصال: يستخدم بعضهم إشارة صريحة إلى السياق الآخر، بينما يمكن للآخرين التواصل ضمنيًا عبر وكيل يتم إنشاء مثيل له على كل جانب.
  • ويختلف توافق المتصفح من حيث لآخر.
مخطّط بياني يعرض الاتصال ثنائي الاتجاه بين مشغّل الصفحة ومشغّل الخدمات وواجهات برمجة التطبيقات المتاحة للمتصفّح

واجهة برمجة تطبيقات قناة البث

دعم المتصفح

  • Chrome: 54.
  • الحافة: 79.
  • Firefox: 38.
  • Safari: الإصدار 15.4.

المصدر

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 لا تتوافق معها حتى الآن.

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

دعم المتصفح

  • Chrome: 40.
  • الحافة: 17.
  • Firefox: 44
  • Safari: الإصدار 11.1.

المصدر

تتيح لك 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 هو خيار جيد للتواصل بسهولة مع جميع علامات التبويب النشطة من مشغّل الخدمات. بطريقة مباشرة نسبيًا. تتوافق واجهة برمجة التطبيقات مع جميع في المتصفّح، ولكن قد لا تكون كل طرقه متوفرة، لذا احرص على التحقق من دعم المتصفح قبل وتنفيذه في موقعك.

قناة الرسائل

دعم المتصفح

  • Chrome: 2-
  • الحافة: 12.
  • Firefox: 41.
  • Safari: الإصدار 5-

المصدر

تتطلب قناة المراسلة تحديد وتمرير منفذ من سياق إلى آخر لإنشاء اتصال ثنائي .

لإعداد القناة، تنشئ الصفحة مثيلاً للعنصر 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 التخزين المؤقت من سياق إلى آخر. سنستكشف في هذا القسم واجهتَي برمجة تطبيقات للتعامل مع وهي: نقص الاتصال والتنزيلات الطويلة.

المزامنة في الخلفية

دعم المتصفح

  • Chrome: 49.
  • الحافة: 79.
  • Firefox: غير مدعوم.
  • Safari: غير متاح.

المصدر

قد يرغب أحد تطبيقات الدردشة في ضمان عدم فقدان الرسائل مطلقًا بسبب الاتصال السيئ. تشير رسالة الأشكال البيانية تتيح لك واجهة برمجة تطبيقات المزامنة في الخلفية تأجيل الإجراءات التي ستتم إعادة محاولة تنفيذها عندما يكون لدى المستخدم اتصال مستقر. يعد ذلك مفيدًا لضمان كل ما يريد المستخدم إرساله، يتم إرساله بالفعل.

بدلاً من الواجهة 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 ميزة "مزامنة الخلفية" للحفاظ على طلبات البحث التي تعذّر تنفيذها بسبب ضعف الاتصال، ثم إعادة المحاولة لاحقًا عندما يكون المستخدم متصلاً بالإنترنت. وبمجرد إجراء العملية، تقوم بإبلاغ النتيجة إلى المستخدم عبر إشعار فوري على الويب:

مخطّط بياني يعرض صفحة تمرّ منفذًا إلى مشغّل الخدمات لإنشاء اتصال ثنائي الاتجاه

استرجاع في الخلفية

دعم المتصفح

  • Chrome: 74.
  • الحافة: 79.
  • Firefox: غير مدعوم.
  • Safari: غير متاح.

المصدر

بالنسبة إلى المهام القصيرة نسبيًا مثل إرسال رسالة أو قائمة عناوين 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}%`);
});
مخطّط بياني يعرض صفحة تمرّ منفذًا إلى مشغّل الخدمات لإنشاء اتصال ثنائي الاتجاه
يتم تعديل واجهة المستخدم للإشارة إلى مدى تقدُّم عملية التنزيل (على اليمين). بفضل عاملي الخدمة، يمكن متابعة تشغيل العملية عند إغلاق جميع علامات التبويب (إلى اليمين).

الخطوات التالية

تعرّفنا في هذا الدليل على الحالة الأكثر شيوعًا للتواصل بين مشغّلي الصفحات وعاملي الخدمات. (الاتصال ثنائي الاتجاه).

في كثير من الأحيان، قد يحتاج المرء إلى سياق واحد فقط للتواصل مع الآخر، دون تلقي الاستجابة. اطلع على الأدلة التالية للحصول على إرشادات حول كيفية تنفيذ تقنيات أحادي الاتجاه في صفحاتك من مشغّل الخدمات وإليها، بالإضافة إلى حالات الاستخدام وأمثلة على الإنتاج:

  • دليل التخزين المؤقت الضمني: الاتصال بمشغّل الخدمات من الصفحة ذاكرة التخزين المؤقت مقدمًا (على سبيل المثال، في سيناريوهات الجلب المسبق).
  • تحديثات البث: الاتصال بالصفحة من عامل الخدمة لإبلاغه بالصفحة عن التحديثات المهمة (على سبيل المثال، يتوفر إصدار جديد من تطبيق الويب).