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

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

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

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

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

Tinder

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

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

Squoosh

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

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

استخدام Workbox

الاستماع إلى أحداث دورة حياة Worker الخدمة

توفّر 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 إلى خيارات استراتيجيتك في جانب worker service:

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 object ويبدأ بإرسال الرسائل إليه. ويمكن لأيّ سياق (مثل صفحة) مهتم بتلقّي هذه الرسائل إنشاء مثيل كائن 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.

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

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

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

قناة الرسائل

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

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

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

لمزيد من أنماط تواصل Window مع الخدمة العاملة، اطّلِع على:

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

مراجع إضافية