هذا الدرس التطبيقي حول الترميز هو جزء من الدورة التدريبية "تطوير تطبيقات الويب التقدّمية" التي طوّرها فريق التدريب في "مطوّرو Google". ستستفيد إلى أقصى حدّ من هذه الدورة التدريبية إذا عملت على إكمال دروس الترميز بالتسلسل.
للاطّلاع على التفاصيل الكاملة حول الدورة التدريبية، يُرجى الانتقال إلى نظرة عامة على تطوير تطبيقات الويب التقدّمية.
مقدمة
يرشدك هذا المختبر إلى كيفية إنشاء عامل خدمة بسيط ويشرح دورة حياة عامل الخدمة.
أهداف الدورة التعليمية
- إنشاء نص برمجي أساسي لعامل الخدمة وتثبيته وإجراء تصحيح أخطاء بسيط
ما يتعين عليك معرفته
- أساسيات JavaScript وHTML
- المفاهيم وبنية ES2015 الأساسية لوعود
- كيفية تفعيل "وحدة تحكّم المطوّرين"
المتطلبات قبل البدء
- جهاز كمبيوتر يمكن الوصول إلى واجهة النظام أو المحطة الطرفية فيه
- الاتصال بالإنترنت
- متصفّح متوافق مع مشغّلي الخدمات
- محرّر نصوص
نزِّل مستودع pwa-training-labs أو استنسِخه من GitHub وثبِّت إصدار LTS من Node.js، إذا لزم الأمر.
انتقِل إلى الدليل service-worker-lab/app/ وابدأ خادم تطوير محليًا:
cd service-worker-lab/app npm install node server.js
يمكنك إيقاف الخادم في أي وقت باستخدام Ctrl-c.
افتح المتصفّح وانتقِل إلى localhost:8081/.
ملاحظة: ألغِ تسجيل أي مشغّلات خدمات وامحُ جميع ذاكرات التخزين المؤقت لمشغّلات الخدمات في localhost لكي لا تتداخل مع المختبر. في "أدوات مطوّري البرامج في Chrome"، يمكنك إجراء ذلك من خلال النقر على محو بيانات الموقع الإلكتروني من قسم محو مساحة التخزين في علامة التبويب التطبيق.
افتح المجلد service-worker-lab/app/ في محرِّر النصوص الذي تفضّله. المجلد app/ هو المكان الذي ستنشئ فيه المختبر.
يحتوي هذا المجلد على ما يلي:
-
below/another.htmlوjs/another.jsوjs/other.jsوother.htmlهي أمثلة على الموارد التي نستخدمها لتجربة نطاق عامل الخدمة - يحتوي المجلد
styles/على أوراق الأنماط المتتالية لهذا الدرس التطبيقي - يحتوي المجلد
test/على ملفات لاختبار مستوى تقدّمك -
index.htmlهي صفحة HTML الرئيسية للموقع الإلكتروني/التطبيق النموذجي -
service-worker.jsهو ملف JavaScript المستخدَم لإنشاء عامل الخدمة - يتتبّع
package.jsonوpackage-lock.jsonحِزم Node المستخدَمة في هذا المشروع -
server.jsهو خادم express بسيط نستخدمه لاستضافة تطبيقنا
افتح service-worker.js في محرِّر النصوص. يُرجى العِلم أنّ الملف فارغ. لم نضيف أي رمز لتشغيله في عامل الخدمة حتى الآن.
افتح index.html في محرِّر النصوص.
داخل علامتَي <script>، أضِف الرمز التالي لتسجيل عامل الخدمة:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('service-worker.js')
.then(registration => {
console.log('Service Worker is registered', registration);
})
.catch(err => {
console.error('Registration failed:', err);
});
});
}احفظ النص البرمجي وأعِد تحميل الصفحة. يجب أن تعرض وحدة التحكّم رسالة تشير إلى أنّه تم تسجيل عامل الخدمة. في Chrome، يمكنك التأكّد من تسجيل عامل الخدمة من خلال فتح "أدوات المطوّرين" (Control + Shift + I على أجهزة Windows وLinux أو ⌘ + alt + I على أجهزة Mac)، والنقر على علامة التبويب "التطبيق"، ثم النقر على خيار عوامل الخدمة. من المفترض أن يظهر لك ما يلي:

اختياري: افتح الموقع الإلكتروني على متصفّح غير متوافق وتأكَّد من أنّ شرط التحقّق من التوافق يعمل.
الشرح
يسجّل الرمز أعلاه الملف service-worker.js كبرنامج عامل للخدمة. يتحقّق أولاً مما إذا كان المتصفّح يتيح استخدام عاملي الخدمة. يجب إجراء ذلك في كل مرة تسجّل فيها مشغّل خدمة لأنّ بعض المتصفّحات قد لا تتوافق مع مشغّلات الخدمات. تسجّل الشفرة بعد ذلك عامل الخدمة باستخدام طريقة register في ServiceWorkerContainer API، والتي يتم تضمينها في واجهة Navigator الخاصة بالنافذة.
تعرض الدالة navigator.serviceWorker.register(...) وعدًا يتم تنفيذه باستخدام العنصر registration بعد تسجيل عامل الخدمة بنجاح. إذا فشل التسجيل، سيتم رفض الوعد.
تؤدي التغييرات في حالة عامل الخدمة إلى تشغيل أحداث في عامل الخدمة.
إضافة أدوات معالجة الأحداث
افتح service-worker.js في محرِّر النصوص.
أضِف أدوات معالجة الأحداث التالية إلى عامل الخدمة:
self.addEventListener('install', event => {
console.log('Service worker installing...');
// Add a call to skipWaiting here
});
self.addEventListener('activate', event => {
console.log('Service worker activating...');
});احفظ الملف.
ألغِ تسجيل مشغّل الخدمات يدويًا وأعِد تحميل الصفحة لتثبيت مشغّل الخدمات المعدَّل وتفعيله. يجب أن يشير سجلّ وحدة التحكّم إلى أنّه تم تسجيل عامل الخدمة الجديد وتثبيته وتفعيله.
ملاحظة: قد يظهر سجلّ التسجيل بترتيب مختلف عن السجلّات الأخرى (التثبيت والتفعيل). يعمل مشغّل الخدمات بشكل متزامن مع الصفحة، لذا لا يمكننا ضمان ترتيب السجلات (يأتي سجلّ التسجيل من الصفحة، بينما يأتي سجلّ التثبيت والتفعيل من مشغّل الخدمات). تحدث أحداث عامل الخدمة، مثل التثبيت والتفعيل وغيرها، بترتيب محدّد داخل عامل الخدمة، ويجب أن تظهر دائمًا بالترتيب المتوقّع.
الشرح
يُصدر عامل الخدمة الحدث install في نهاية عملية التسجيل. في الرمز أعلاه، يتم تسجيل رسالة داخل أداة معالجة الحدث install، ولكن في تطبيق حقيقي، سيكون هذا مكانًا جيدًا لتخزين مواد العرض الثابتة مؤقتًا.
عند تسجيل مشغّل خدمات، يتأكّد المتصفّح مما إذا كان مشغّل الخدمات جديدًا (إما لأنّه يختلف عن مشغّل الخدمات المثبَّت سابقًا أو لأنّه لا يتوفّر مشغّل خدمات مسجَّل لهذا الموقع الإلكتروني). إذا كان عامل الخدمة جديدًا (كما هو الحال في هذا المثال)، سيثبّته المتصفّح.
يُصدر مشغّل الخدمات حدث activate عندما يتحكّم في الصفحة. يسجّل الرمز البرمجي أعلاه رسالة هنا، ولكن غالبًا ما يُستخدَم هذا الحدث لتعديل الذاكرات المؤقتة.
يمكن تفعيل عامل خدمة واحد فقط في كل مرة لنطاق معيّن (راجِع استكشاف نطاق عامل الخدمة)، لذا لا يتم تفعيل عامل الخدمة الذي تم تثبيته حديثًا إلا بعد التوقف عن استخدام عامل الخدمة الحالي. لهذا السبب، يجب إغلاق جميع الصفحات التي يتحكّم فيها مشغّل الخدمات قبل أن يتمكّن مشغّل خدمات جديد من السيطرة عليها. بما أنّنا ألغينا تسجيل مشغّل الخدمات الحالي، تم تفعيل مشغّل الخدمات الجديد على الفور.
ملاحظة: لا يكفي مجرد إعادة تحميل الصفحة لنقل التحكّم إلى مشغّل خدمات جديد، لأنّه سيتم طلب الصفحة الجديدة قبل إلغاء تحميل الصفحة الحالية، ولن يكون هناك وقت لا يكون فيه مشغّل الخدمات القديم قيد الاستخدام.
ملاحظة: يمكنك أيضًا تفعيل عامل خدمة جديد يدويًا باستخدام أداة المطوّرين في بعض المتصفحات وبرمجيًا باستخدام skipWaiting()، وهو ما سنتناوله في الفقرة 3.4.
تعديل عامل الخدمة
أضِف التعليق التالي في أي مكان في service-worker.js:
// I'm a new service workerاحفظ الملف وأعِد تحميل الصفحة. اطّلِع على السجلّات في وحدة التحكّم، ولاحظ أنّ عامل الخدمة الجديد يتم تثبيته ولكن لا يتم تفعيله. في Chrome، يمكنك الاطّلاع على عامل الخدمة في انتظار التفعيل في علامة التبويب التطبيق في "أدوات مطوّري البرامج".

أغلِق جميع الصفحات المرتبطة ببرنامج عامل الخدمة. بعد ذلك، أعِد فتح localhost:8081/. يجب أن يشير سجلّ وحدة التحكّم إلى أنّه تم تفعيل عامل الخدمة الجديد الآن.
ملاحظة: إذا كنت تتلقّى نتائج غير متوقّعة، تأكَّد من إيقاف ذاكرة التخزين المؤقت لبروتوكول HTTP في أدوات المطوّرين.
الشرح
يرصد المتصفّح اختلافًا في البايت بين ملف مشغّل الخدمات الجديد والملف الحالي (بسبب التعليق المُضاف)، لذا يتم تثبيت مشغّل الخدمات الجديد. بما أنّه لا يمكن تفعيل أكثر من عامل خدمة واحد في كل مرة (لنطاق معيّن)، حتى إذا تم تثبيت عامل الخدمة الجديد، لن يتم تفعيله إلى أن يتوقف استخدام عامل الخدمة الحالي. من خلال إغلاق جميع الصفحات التي يتحكّم فيها مشغّل الخدمات القديم، يمكننا تفعيل مشغّل الخدمات الجديد.
تخطّي مرحلة الانتظار
من الممكن أن يتم تفعيل عامل خدمة جديد على الفور، حتى إذا كان عامل خدمة حالي متوفّرًا، وذلك عن طريق تخطّي مرحلة الانتظار.
في service-worker.js، أضِف طلبًا إلى skipWaiting في معالج الحدث install:
self.skipWaiting();احفظ الملف وأعِد تحميل الصفحة. لاحظ أنّ عامل الخدمة الجديد يتم تثبيته وتفعيله على الفور، حتى إذا كان عامل خدمة سابق يتحكّم في الصفحة.
الشرح
تسمح طريقة skipWaiting() بتفعيل عامل الخدمة فور انتهاء عملية التثبيت. أداة معالجة حدث التثبيت هي مكان شائع لوضع استدعاء skipWaiting()، ولكن يمكن استدعاؤها في أي مكان أثناء مرحلة الانتظار أو قبلها. يمكنك الاطّلاع على هذه المستندات لمعرفة المزيد حول الحالات المناسبة لاستخدام skipWaiting() وكيفية استخدامه. بالنسبة إلى بقية المختبر، يمكننا الآن اختبار رمز مشغّل الخدمات الجديد بدون إلغاء تسجيل مشغّل الخدمات يدويًا.
لمزيد من المعلومات
يمكن أن تعمل مشغّلات الخدمات كوكيل بين تطبيق الويب والشبكة.
لنضِف أداة معالجة لجلب البيانات من أجل اعتراض الطلبات من نطاقنا.
أضِف الرمز التالي إلى service-worker.js:
self.addEventListener('fetch', event => {
console.log('Fetching:', event.request.url);
});احفظ النص البرمجي وأعِد تحميل الصفحة لتثبيت عامل الخدمة المعدَّل وتفعيله.
تحقَّق من وحدة التحكّم ولاحظ أنّه لم يتم تسجيل أي أحداث جلب. أعِد تحميل الصفحة وتحقّق من وحدة التحكّم مرة أخرى. من المفترض أن تظهر لك أحداث الجلب هذه المرة للصفحة ومواد عرضها (مثل CSS).
انقر على الروابط صفحة أخرى وصفحة أخرى ورجوع.
ستظهر لك أحداث الجلب في وحدة التحكّم لكل صفحة ومواد عرضها. هل جميع السجلات منطقية؟
ملاحظة: إذا زرت صفحة ولم يتم إيقاف ذاكرة التخزين المؤقت لبروتوكول HTTP، قد يتم تخزين أصول CSS وJavaScript مؤقتًا على جهازك. في حال حدوث ذلك، لن ترى أحداث جلب لهذه الموارد.
الشرح
يتلقّى عامل الخدمة حدث جلب لكل طلب HTTP يجريه المتصفّح ويكون ضمن نطاقه. يحتوي عنصر حدث الجلب على الطلب. يشبه الاستماع إلى أحداث الجلب في عامل الخدمة الاستماع إلى أحداث النقر في نموذج العناصر في المستند. في الرمز البرمجي، عندما يحدث حدث جلب، نسجّل عنوان URL المطلوب في وحدة التحكّم (في الواقع، يمكننا أيضًا إنشاء ردّ مخصّص خاص بنا وإرجاعه باستخدام موارد عشوائية).
لماذا لم يتم تسجيل أي أحداث جلب عند إعادة التحميل الأولى؟ بشكلٍ تلقائي، لن تمر أحداث الجلب من صفحة معيّنة عبر مشغّل الخدمات ما لم يمر طلب الصفحة نفسه عبر مشغّل الخدمات. يضمن ذلك الاتساق في موقعك الإلكتروني، فإذا تم تحميل صفحة بدون مشغّل الخدمات، سيتم تحميل الموارد الفرعية أيضًا.
لمزيد من المعلومات
رمز الحلّ
للحصول على نسخة من الرمز البرمجي، انتقِل إلى المجلد 04-intercepting-network-requests/.
تتضمّن مشغّلات الخدمات نطاقًا. يحدّد نطاق مشغّل الخدمات المسارات التي يعترض مشغّل الخدمات الطلبات منها.
العثور على النطاق
عدِّل رمز التسجيل في index.html باستخدام:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('service-worker.js')
.then(registration => {
console.log('SW registered with scope:', registration.scope);
})
.catch(err => {
console.error('Registration failed:', err);
});
});
}أعِد تحميل المتصفّح. لاحظ أنّ وحدة التحكّم تعرض نطاق مشغّل الخدمات (في هذه الحالة هو http://localhost:8081/).
الشرح
يتم حلّ الوعد الذي تم إرجاعه من خلال register() إلى كائن التسجيل الذي يحتوي على نطاق عامل الخدمة.
النطاق التلقائي هو مسار ملف عامل الخدمة، ويمتد إلى جميع الأدلة الفرعية. لذلك، يتحكّم مشغّل الخدمات في الدليل الجذر للتطبيق في الطلبات الواردة من جميع الملفات في التطبيق.
نقل عامل الخدمة
انقل الملف service-worker.js إلى الدليل below/ وعدِّل عنوان URL الخاص ببرنامج الخدمة في رمز التسجيل في index.html.
ألغِ تسجيل مشغّل الخدمات الحالي في المتصفّح وأعِد تحميل الصفحة.
تعرض وحدة التحكّم أنّ نطاق عامل الخدمة أصبح الآن http://localhost:8081/below/. في Chrome، يمكنك أيضًا الاطّلاع على نطاق عامل الخدمة في علامة تبويب التطبيق ضمن "أدوات مطوّري البرامج":

بالعودة إلى الصفحة الرئيسية، انقر على صفحة أخرى وصفحة أخرى ورجوع. ما هي طلبات الجلب التي يتم تسجيلها؟ وما هي الميزات غير المشتركة؟
الشرح
نطاق عامل الخدمة التلقائي هو مسار ملف عامل الخدمة. بما أنّ ملف عامل الخدمة أصبح الآن في below/، هذا هو نطاقه. تسجّل وحدة التحكّم الآن أحداث الجلب فقط لكل من another.html وanother.css وanother.js، لأنّ هذه هي الموارد الوحيدة ضمن نطاق مشغّل الخدمات.
تحديد نطاق عشوائي
انقل عامل الخدمة مرة أخرى إلى دليل جذر المشروع (app/) وعدِّل عنوان URL الخاص بعامل الخدمة في رمز التسجيل في index.html.
استخدِم المرجع على شبكة مطوّلي Mozilla لضبط نطاق عامل الخدمة على الدليل below/ باستخدام المَعلمة الاختيارية في register().
ألغِ تسجيل مشغّل الخدمات وأعِد تحميل الصفحة. انقر على صفحة أخرى وصفحة أخرى ورجوع.
مرة أخرى، يوضّح المتصفّح أنّ نطاق عامل الخدمة أصبح الآن http://localhost:8081/below/، ويسجّل أحداث الجلب فقط لـ another.html وanother.css وanother.js.
الشرح
يمكنك ضبط نطاق اختياري عن طريق إدخال مَعلمة إضافية عند التسجيل، على سبيل المثال:
navigator.serviceWorker.register('/service-worker.js', {
scope: '/kitten/'
});في المثال أعلاه، تم ضبط نطاق عامل الخدمة على /kitten/. يعترض مشغّل الخدمات الطلبات من الصفحات في /kitten/ و/kitten/lower/، ولكن ليس من صفحات مثل /kitten أو /.
ملاحظة: لا يمكنك ضبط نطاق عشوائي أعلى من الموقع الجغرافي الفعلي لبرنامج عامل الخدمة. ومع ذلك، إذا كان عامل الخدمة نشطًا على عميل يتم عرضه باستخدام العنوان Service-Worker-Allowed، يمكنك تحديد نطاق أقصى لعامل الخدمة هذا أعلى موقع عامل الخدمة.
لمزيد من المعلومات
رمز الحلّ
للحصول على نسخة من الرمز البرمجي، انتقِل إلى المجلد solution/.
أصبح لديك الآن عامل خدمة بسيط يعمل ويمكنك فهم دورة حياة عامل الخدمة.
لمزيد من المعلومات
للاطّلاع على جميع دروس البرمجة في دورة تدريب تطبيقات الويب التقدّمية، راجِع درس البرمجة الترحيبي للدورة التدريبية.