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

tl;dr

بدءًا من إصدار Chrome 68، لن يتم تلقائيًا تنفيذ طلبات 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.

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

قبل الإصدار Chrome 68، كان يتم طلب تحديث /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). هذا هو الإعداد التلقائي، ويتطابق مع السلوك بدءًا من الإصدار 68 من Chrome.

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

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

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

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

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

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

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

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

يتطابق سلوك Chrome 78 مع ما نفّذه Firefox قبل عدة أعوام، في الإصدار 56 من Firefox. ينفذ 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' بشكل صريح عند تسجيل مشغّل الخدمة.

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

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

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

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

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

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

محتوى إضافي للقراءة

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