بث التحديثات على الصفحات التي تتضمن مشغّلي الخدمات

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

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

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

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

حالات الإنتاج

Tinder

يستخدم تطبيق Tinder التقدّمي على الويب workbox-window للاستماع إلى لحظات مهمة في دورة حياة مشغّل الخدمات من الصفحة ("تم التثبيت" و"تم التحكّم" و"تم التفعيل"). بهذه الطريقة، عندما يبدأ عامل خدمة جديد بالعمل، سيظهر بانر "يتوفّر تحديث" ليتمكّن المستخدم من إعادة تحميل تطبيق الويب التقدّمي والوصول إلى أحدث الميزات:

لقطة شاشة لوظيفة "يتوفّر تحديث" في تطبيق الويب من Tinder
في تطبيق Tinder التقدّمي على الويب، يخبر مشغّل الخدمات الصفحة بأنّ إصدارًا جديدًا أصبح جاهزًا، وتعرض الصفحة للمستخدمين بانر "يتوفّر تحديث".

Squoosh

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

لقطة شاشة لوظيفة "جاهز للعمل بلا إنترنت" في تطبيق Squoosh على الويب
في تطبيق Squoosh التقدّمي على الويب، يرسل مشغّل الخدمات إشعارًا بتحديث الصفحة عندما يصبح التخزين المؤقت جاهزًا، وتعرض الصفحة إشعارًا مؤقتًا "جاهز للعمل بلا إنترنت".

استخدام Workbox

الاستماع إلى أحداث مراحل نشاط عامل الخدمة

توفّر workbox-window واجهة مباشرة للاستماع إلى أحداث مهمة في دورة حياة مشغّل الخدمات. تستخدم المكتبة في الخلفية واجهات برمجة تطبيقات من جهة العميل، مثل updatefound وstatechange، وتوفّر أدوات معالجة أحداث ذات مستوى أعلى في الكائن workbox-window، ما يسهّل على المستخدم استخدام هذه الأحداث.

يتيح لك رمز الصفحة التالي رصد كل مرة يتم فيها تثبيت إصدار جديد من عامل الخدمة، وبالتالي يمكنك إبلاغ المستخدم بذلك:

const wb = new Workbox('/sw.js');

wb.addEventListener('installed', (event) => {
  if (event.isUpdate) {
    // Show "Update App" banner
  }
});

wb.register();

إبلاغ الصفحة بالتغييرات في بيانات ذاكرة التخزين المؤقت

تقدّم حزمة Workbox workbox-broadcast-update طريقة عادية لإعلام عملاء النوافذ بأنّه تم تعديل استجابة مخزّنة مؤقتًا. ويتم استخدامها في أغلب الأحيان مع استراتيجية StaleWhileRevalidate.

لبث التحديثات، أضِف broadcastUpdate.BroadcastUpdatePlugin إلى خيارات الاستراتيجية في ملف عامل الخدمة:

import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
import {BroadcastUpdatePlugin} from 'workbox-broadcast-update';

registerRoute(
  ({url}) => url.pathname.startsWith('/api/'),
  new StaleWhileRevalidate({
    plugins: [
      new BroadcastUpdatePlugin(),
    ],
  })
);

في تطبيق الويب، يمكنك الاستماع إلى هذه الأحداث على النحو التالي:

navigator.serviceWorker.addEventListener('message', async (event) => {
  // Optional: ensure the message came from workbox-broadcast-update
  if (event.data.meta === 'workbox-broadcast-update') {
    const {cacheName, updatedUrl} = event.data.payload;

    // Do something with cacheName and updatedUrl.
    // For example, get the cached content and update
    // the content on the page.
    const cache = await caches.open(cacheName);
    const updatedResponse = await cache.match(updatedUrl);
    const updatedText = await updatedResponse.text();
  }
});

استخدام واجهات برمجة التطبيقات في المتصفّح

إذا لم تكن الوظائف التي يوفّرها Workbox كافية لتلبية احتياجاتك، استخدِم واجهات برمجة التطبيقات التالية للمتصفّح لتنفيذ "عمليات البث المباشر للتحديثات":

Broadcast Channel API

ينشئ عامل الخدمة عنصر BroadcastChannel ويبدأ في إرسال الرسائل إليه. يمكن لأي سياق (مثل صفحة) مهتم بتلقّي هذه الرسائل إنشاء عنصر BroadcastChannel وتنفيذ معالج رسائل لتلقّي الرسائل.

لإعلام الصفحة عند تثبيت مشغّل خدمات جديد، استخدِم الرمز التالي:

// Create Broadcast Channel to send messages to the page
const broadcast = new BroadcastChannel('sw-update-channel');

self.addEventListener('install', function (event) {
  // Inform the page every time a new service worker is installed
  broadcast.postMessage({type: 'CRITICAL_SW_UPDATE'});
});

تستمع الصفحة إلى هذه الأحداث من خلال الاشتراك في sw-update-channel:

// Create Broadcast Channel and listen to messages sent to it
const broadcast = new BroadcastChannel('sw-update-channel');

broadcast.onmessage = (event) => {
  if (event.data && event.data.type === 'CRITICAL_SW_UPDATE') {
    // Show "update to refresh" banner to the user.
  }
};

هذه تقنية بسيطة، ولكنّها محدودة بسبب عدم توفّرها في بعض المتصفّحات، ففي وقت كتابة هذا المقال، لا يتيح متصفّح Safari استخدام واجهة برمجة التطبيقات هذه.

Client API

توفّر Client API طريقة مباشرة للتواصل مع عدة برامج عميلة من عامل الخدمة من خلال تكرار مصفوفة من عناصر Client.

استخدِم رمز عامل الخدمة التالي لإرسال رسالة إلى آخر علامة تبويب تم التركيز عليها:

// 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'});
  }
});

تنفّذ الصفحة معالج رسائل لاعتراض هذه الرسائل:

// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
     if (event.data && event.data.type === 'MSG_ID') {
         // Process response
   }
};

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

قناة الرسائل

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

const messageChannel = new MessageChannel();

// Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
  messageChannel.port2,
]);

تستمع الصفحة إلى الرسائل من خلال تنفيذ معالج "onmessage" على هذا المنفذ:

// Listen to messages
messageChannel.port1.onmessage = (event) => {
  // Process message
};

يتلقّى مشغّل الخدمات المنفذ ويحفظ مرجعًا إليه:

// Initialize
let communicationPort;

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PORT_INITIALIZATION') {
    communicationPort = event.ports[0];
  }
});

يمكنه من تلك النقطة إرسال رسائل إلى الصفحة، وذلك عن طريق استدعاء postMessage() في مرجع المنفذ:

// Communicate
communicationPort.postMessage({type: 'MSG_ID' });

قد يكون تنفيذ MessageChannel أكثر تعقيدًا بسبب الحاجة إلى تهيئة المنافذ، ولكن جميع المتصفحات الرئيسية تتيح استخدامه.

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

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

للاطّلاع على المزيد من أنماط التواصل بين النافذة ومشغّل الخدمات، يُرجى الانتقال إلى:

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

مراجع إضافية