مشغّلو الخدمات الجُدد تلقائيًا

النص المختصر

اعتبارًا من الإصدار 68 من Chrome، لن تتم تلبية طلبات HTTP التي تتحقّق من توفّر تحديثات لنص عامل الخدمة تلقائيًا من خلال ذاكرة التخزين المؤقت لبروتوكول HTTP. يعالج هذا الحلّ نقطة ضعف شائعة لدى المطوّرين، حيث قد يؤدي ضبط عنوان Cache-Control غير مقصود في نص عامل الخدمة إلى تأخُّر التحديثات.

إذا سبق لك إيقاف ميزة التخزين المؤقت لبروتوكول HTTP لنص /service-worker.js عن طريق عرضه مع Cache-Control: max-age=0، من المفترض ألا تلاحظ أي تغييرات بسبب السلوك التلقائي الجديد.

بالإضافة إلى ذلك، اعتبارًا من الإصدار 78 من Chrome، سيتم تطبيق المقارنة بتقسيم البيانات إلى وحدات أساسية على النصوص البرمجية التي يتم تحميلها في عامل خدمة من خلال importScripts(). سيؤدي أي تغيير يتم إجراؤه على نص برمجي مستورَد إلى بدء عملية تعديل عامل الخدمة، تمامًا كما لو تم إجراء تغيير على عامل الخدمة من المستوى الأعلى.

الخلفية

في كل مرة تنتقل فيها إلى صفحة جديدة تقع ضمن نطاق عامل خدمة، يمكنك استدعاء registration.update() بشكل صريح من JavaScript، أو عندما يتم "تنشيط" عامل الخدمة من خلال حدث push أو sync، سيطلب المتصفح بشكل موازٍ مورد JavaScript الذي تم تمريره في الأصل إلى دعوة navigator.serviceWorker.register() للبحث عن تعديلات على نص عامل الخدمة.

لأغراض هذه المقالة، لنفترض أنّ عنوان URL الخاص بالملف هو /service-worker.js وأنّه يحتوي على طلب واحد إلى importScripts()، الذي يحمّل رمزًا إضافيًا يتم تشغيله داخل الخدمة العاملة:

// Inside our /service-worker.js file:
importScripts('path/to/import.js');

// Other top-level code goes here.

ما الذي سيتغيّر؟

قبل الإصدار 68 من Chrome، كان يتم إرسال طلب التعديل لـ /service-worker.js من خلال ذاكرة التخزين المؤقت لبروتوكول HTTP (كما هو الحال مع معظم عمليات الجلب). وهذا يعني أنّه إذا تم إرسال النص البرمجي في الأصل باستخدام Cache-Control: max-age=600، لن يتم إرسال التعديلات خلال الـ 600 ثانية التالية (10 دقائق) إلى الشبكة، لذا قد لا يتلقّى المستخدم أحدث إصدار من الخدمة العاملة. ومع ذلك، إذا كان max-age أكبر من 86400 (24 ساعة)، سيتم التعامل معه كما لو كان 86400، لتجنّب تثبيت المستخدمين على إصدار معيّن إلى الأبد.

اعتبارًا من الإصدار 68، سيتم تجاهل ذاكرة التخزين المؤقت لبروتوكول HTTP عند طلب تعديلات على ملف برمجي الخدمة، لذا قد تلاحظ تطبيقات الويب الحالية زيادة في وتيرة طلبات ملف برمجي الخدمة. وسيظلّ إرسال طلبات importScripts من خلال ذاكرة التخزين المؤقت لبروتوكول HTTP. ولكن هذا هو الإعداد التلقائي فقط. يتوفّر خيار تسجيل جديد، updateViaCache، يتيح التحكّم في هذا السلوك.

updateViaCache

يمكن للمطوّرين الآن إدخال خيار جديد عند استدعاء navigator.serviceWorker.register(): المَعلمة updateViaCache. يمكن أن تأخذ إحدى القيم الثلاث: 'imports' أو 'all' أو 'none'.

وتحدِّد القيم ما إذا كان ذاكرة التخزين المؤقت لبروتوكول HTTP المعتادة في المتصفّح تُستخدَم عند تقديم طلب HTTP للتحقّق من توفّر موارد عامل الخدمة المعدَّلة.

  • عند ضبط القيمة على 'imports'، لن تتم استشارة ذاكرة التخزين المؤقت لبروتوكول HTTP أبدًا عند البحث عن تحديثات في النص البرمجي /service-worker.js، ولكن سيتم الرجوع إليها عند جلب أي نصوص برمجية مستورَدة (path/to/import.js في مثالنا). هذا هو الإعداد التلقائي، وهو مطابق للسلوك الذي بدأ في Chrome 68.

  • عند ضبط القيمة على 'all'، سيتم الرجوع إلى ذاكرة التخزين المؤقت لبروتوكول HTTP عند تقديم طلبات لكل من ملف /service-worker.js النصي العميق ولأي ملفات نصية مستورَدة داخل عامل تدخُّل الخدمة، مثل path/to/import.js. يتطابق هذا الخيار مع السلوك السابق في Chrome، قبل الإصدار 68.

  • عند ضبط القيمة على 'none'، لن تتم الرجوع إلى ذاكرة التخزين المؤقت لبروتوكول HTTP عند تقديم طلبات إما لملف /service-worker.js من المستوى الأعلى أو لأي نصوص برمجية مستورَدة، مثل path/to/import.js.

على سبيل المثال، سيسجّل الرمز البرمجي التالي عامل خدمة، ويضمن عدم الرجوع إلى ذاكرة التخزين المؤقت لبروتوكول HTTP عند التحقّق من توفّر تحديثات إما لنص /service-worker.js البرمجي أو لأي ملف importScripts() برمجي تتم الإشارة إليه من خلال importScripts() داخل /service-worker.js:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js', {
    updateViaCache: 'none',
    // Optionally, set 'scope' here, if needed.
  });
}

البحث عن تحديثات للنصوص البرمجية المستورَدة

قبل الإصدار 78 من Chrome، كان يتم استرداد أي نص برمجي لعامل الخدمة يتم تحميله من خلال importScripts() مرة واحدة فقط (يتم التحقّق أولاً من ذاكرة التخزين المؤقت لبروتوكول HTTP أو من خلال الشبكة، استنادًا إلى إعدادات updateViaCache). وبعد هذا الإجراء الأولي لمحاولة استرجاع البيانات، سيخزّنها المتصفّح داخليًا ولن يتم إعادة جلبها مطلقًا.

كانت الطريقة الوحيدة لإجبار عامل الخدمة المثبَّت على رصد التغييرات في النص البرمجي المستورَد هي تغيير عنوان URL للنص البرمجي، وذلك عادةً إما عن طريق إضافة قيمة semver (مثل importScripts('https://example.com/v1.1.0/index.js')) أو عن طريق تضمين تجزئة للمحتوى (مثل importScripts('https://example.com/index.abcd1234.js')). ويؤدي تغيير عنوان URL المستورَد إلى تغيير محتوى النص البرمجي لعامل الخدمة من المستوى الأعلى، ما يؤدي بدوره إلى بدء عملية تحديث عامل الخدمة.

بدءًا من الإصدار 78 من Chrome، في كل مرة يتم فيها التحقّق من توفّر تحديث لملف عامل الخدمة في المستوى الأعلى، سيتم إجراء عمليات تحقّق في الوقت نفسه لتحديد ما إذا كانت محتويات أي نصوص برمجية مستورَدة قد تغيّرت أم لا. استنادًا إلى عناوين Cache-Control المستخدَمة، قد تتم معالجة عمليات التحقّق من النصوص البرمجية المستورَدة من قِبل ملف التخزين المؤقت لبروتوكول HTTP إذا تم ضبط updateViaCache على 'all' أو 'imports' (وهي القيمة التلقائية)، أو قد تتم عمليات التحقّق مباشرةً من الشبكة إذا تم ضبط updateViaCache على 'none'.

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

يتطابق سلوك الإصدار 78 من Chrome مع السلوك الذي نفَّذه Firefox قبل عدة سنوات في الإصدار 56. ينفِّذ Safari هذا السلوك أيضًا.

ما الإجراءات التي يجب على المطوّرين اتّخاذها؟

إذا أوقفت ميزة التخزين المؤقت لبروتوكول HTTP لنص /service-worker.js البرمجي بشكلٍ فعّال من خلال عرضه مع Cache-Control: max-age=0 (أو قيمة مشابهة)، من المفترض ألا تلاحظ أي تغييرات بسبب السلوك التلقائي الجديد.

في حال عرض نص /service-worker.js البرمجي مع تفعيل ميزة التخزين المؤقت لبروتوكول HTTP، سواء عمدًا أو لأنّها الإعداد التلقائي لخدمة الاستضافة، قد تبدأ في ملاحظة زيادة في عدد طلبات HTTP الإضافية التي يتم إجراؤها على /service-worker.js ضد خادمك، وهي الطلبات التي كان يتم تنفيذها من خلال ذاكرة التخزين المؤقت لبروتوكول HTTP. إذا كنت تريد مواصلة السماح لقيمة العنوان Cache-Control بالتأثير في حداثة /service-worker.js، عليك البدء في ضبط updateViaCache: 'all' بشكل صريح عند تسجيل worker الخدمة.

بما أنّه قد يكون هناك عدد كبير من المستخدمين الذين يستخدمون إصدارات قديمة من المتصفّحات، يُنصح باستمرار ضبط عنوان HTTP Cache-Control: max-age=0 في نصوص worker البرمجية، حتى إذا كانت المتصفّحات الأحدث قد تتجاهلها.

يمكن للمطوّرين استخدام هذه الفرصة لتحديد ما إذا كانوا يريدون إيقاف ميزة التخزين المؤقت لبروتوكول HTTP في ملفّات برمجية مستورَدة بشكل صريح الآن، وإضافة updateViaCache: 'none' إلى تسجيل عامل الخدمة إذا كان ذلك مناسبًا.

عرض النصوص البرمجية المستورَدة

اعتبارًا من الإصدار 78 من Chrome، قد يلاحظ المطوّرون زيادة في عدد طلبات HTTP الواردة لتحميل موارد عبر importScripts()، لأنّه سيتم الآن التحقّق منها بحثًا عن التحديثات.

إذا كنت تريد تجنُّب هذه الزيارات الإضافية عبر HTTP، اضبط عناوين Cache-Control صالحة لفترة طويلة عند عرض النصوص البرمجية التي تتضمّن semver أو تجزئات في عناوين URL الخاصة بها، واعتمد على السلوك التلقائي updateViaCache ل'imports'.

بدلاً من ذلك، إذا أردت التحقّق من نصوصك البرمجية المستورَدة بحثًا عن التحديثات المتكرّرة، تأكَّد من عرضها باستخدام Cache-Control: max-age=0 أو استخدام updateViaCache: 'none'.

مراجع إضافية

ننصحك بقراءة مقالتَي "دورة حياة Worker الخدمة" و "أفضل الممارسات المتعلّقة بالخَزّن المؤقت ومشاكل max-age"، كلتاهما من تأليف "جاك أرشيبالد"، وذلك لجميع المطوّرين الذين ينشرون أي محتوى على الويب.