معالجة تحديثات مشغّلي الخدمات على الفور

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

في كثير من الحالات، قد يكون من الجيد السماح بحدوث ذلك في الوقت المناسب، ولكن في بعض الحالات، قد تحتاج إلى إعلام المستخدم بوجود تحديث معلَّق لعامل الخدمة، ثم تشغيل عملية التبديل بشكل تلقائي إلى مشغِّل الخدمات الجديد. لتنفيذ ذلك، عليك إضافة بعض الرموز في صفحتك ومشغّل الخدمات.

الرمز الذي يجب وضعه في صفحتك

يعمل الرمز التالي في عنصر <script> مضمّن باستخدام وحدات JavaScript التي تم استيرادها من إصدار workbox-window مستضاف على شبكة توصيل المحتوى (CDN). إنّها تسجّل مشغّل خدمات يستخدم "workbox-window"، وسيستجيب إذا توقّف عامل تشغيل الخدمة في مرحلة الانتظار. عند العثور على عامل خدمة انتظار، يُعلِم هذا الرمز المستخدم بوجود إصدار محدَّث من الموقع الإلكتروني ويطلب منه إعادة التحميل.

<!-- This script tag uses JavaScript modules, so the proper `type` attribute value is required -->
<script type="module">
  // This code sample uses features introduced in Workbox v6.
  import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-window.prod.mjs';

  if ('serviceWorker' in navigator) {
    const wb = new Workbox('/sw.js');
    let registration;

    const showSkipWaitingPrompt = async (event) => {
      // Assuming the user accepted the update, set up a listener
      // that will reload the page as soon as the previously waiting
      // service worker has taken control.
      wb.addEventListener('controlling', () => {
        // At this point, reloading will ensure that the current
        // tab is loaded under the control of the new service worker.
        // Depending on your web app, you may want to auto-save or
        // persist transient state before triggering the reload.
        window.location.reload();
      });

      // When `event.wasWaitingBeforeRegister` is true, a previously
      // updated service worker is still waiting.
      // You may want to customize the UI prompt accordingly.

      // This code assumes your app has a promptForUpdate() method,
      // which returns true if the user wants to update.
      // Implementing this is app-specific; some examples are:
      // https://open-ui.org/components/alert.research or
      // https://open-ui.org/components/toast.research
      const updateAccepted = await promptForUpdate();

      if (updateAccepted) {
        wb.messageSkipWaiting();
      }
    };

    // Add an event listener to detect when the registered
    // service worker has installed but is waiting to activate.
    wb.addEventListener('waiting', (event) => {
      showSkipWaitingPrompt(event);
    });

    wb.register();
  }
</script>

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

الرمز الذي يجب وضعه في مشغّل الخدمات

بعد حصولك على الرمز من القسم السابق في صفحتك، ستحتاج إلى إضافة رمز إلى عامل الخدمة يتيح له معرفة الوقت الذي يجب فيه تخطي مرحلة الانتظار. في حال استخدام generateSW من workbox-build وتم ضبط الخيار skipWaiting على false (الإعداد التلقائي)، يمكنك المتابعة لأنّه سيتم تضمين الرمز أدناه تلقائيًا في ملف مشغّل الخدمات الذي تم إنشاؤه.

إذا كنت تكتب مشغّل الخدمات الخاص بك، ربما مع إحدى أدوات إنشاء Workbox في وضع injectManifest، ستحتاج إلى إضافة الرمز التالي بنفسك:

addEventListener('message', (event) => {
  if (event.data && event.data.type === 'SKIP_WAITING') {
    self.skipWaiting();
  }
});

سيؤدي ذلك إلى الاستماع إلى الرسائل المُرسَلة إلى مشغّل الخدمات من workbox-window بقيمة type بقيمة SKIP_WAITING، وعند حدوث ذلك، يتم الاتصال برقم self.skipWaiting(). طريقة messageSkipWaiting() في workbox-window، والواردة في نموذج الرمز السابق، هي المسؤولة عن إرسال هذه الرسالة.

هل يجب عرض طلب؟

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

  • أنت تستخدم التخزين المسبق على نطاق واسع. بالنسبة إلى مواد العرض الثابتة، يمكن أن تحدث مشاكل لاحقًا في حال كنت تستخدِم استراتيجية تركّز على الشبكة أولاً أو على الشبكة فقط لطلبات التنقّل مع استخدام التحميل الكسول لمواد العرض الثابتة. وقد يتسبّب ذلك في مواقف قد تتغيّر فيها مواد العرض ذات الإصدارات، ولا يخزّنها مشغّل الخدمات مؤقتًا. قد يؤدي تقديم زر إعادة التحميل هنا إلى تجنّب بعض السلوكيات غير المتوقعة.
  • إذا كنت تعرض رمز HTML مخزَّن مؤقتًا. وفي هذه الحالة، يجب بشدة عرض زر إعادة التحميل عند تحديث مشغّل الخدمات، لأنّه لن يتم التعرّف على التعديلات التي يتم إجراؤها على رمز HTML هذا إلى أن يتولى عامل الخدمة المحدَّث مسؤولية التحكّم.
  • إذا لم تكن تعتمد بشكل أساسي على التخزين المؤقت في وقت التشغيل عند تخزين الموارد مؤقتًا في وقت التشغيل، لن تحتاج إلى إبلاغ المستخدم بضرورة إعادة تحميلها. ومع تغيُّر مواد العرض ذات الإصدارات المختلفة، ستتم إضافتها إلى ذاكرة التخزين المؤقت لبيئة التشغيل في الوقت المناسب، بافتراض أنّ طلبات التنقّل تستخدم استراتيجية تركّز على الشبكة أولاً أو على الشبكة فقط.
  • عند استخدام استراتيجية الإصدار القديم أثناء إعادة التحقّق، يمكنك استخدام وحدة workbox-broadcast-update لإشعار المستخدمين بالتعديلات على مشغّل الخدمة.

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