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

النص المختصر

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