دليل التخزين المؤقت الأمري

قد تحتاج بعض المواقع الإلكترونية إلى التواصل مع مشغّل الخدمات بدون الحاجة إلى الإعلام بالنتيجة. وإليك بعض الأمثلة:

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

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

مخطّط بياني لصفحة تطلب من مشغّل خدمة تخزين موارد مؤقتًا

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

طلب الإنتاج

نفَّذ موقع 1-800-Flowers.com التخزين المؤقت الإلزامي (التحميل المُسبَق) باستخدام مهام الخدمة من خلال postMessage() لتحميل المشتريات الأكثر رواجًا في صفحات الفئات مُسبَقًا لتسريع عملية التنقّل اللاحقة إلى صفحات تفاصيل المنتجات.

شعار 1-800 Flowers

ويستخدمون نهجًا مختلطًا لتحديد العناصر التي سيتم تحميلها مسبقًا:

  • في وقت تحميل الصفحة، يطلبون من عامل الخدمة استرداد بيانات JSON الخاصة بأكبر 9 عناصر، وإضافة عناصر الاستجابة الناتجة إلى ذاكرة التخزين المؤقت.
  • بالنسبة إلى العناصر المتبقية، يتم الاستماع إلى الحدث mouseover ، بحيث يمكن للمستخدِم عند تحريك المؤشر فوق عنصر أن يشغّل عملية جلب للمورد عند الطلب.

وتستخدم Cache API لتخزين استجابات JSON:

شعار 1-800 Flowers
التحميل المُسبَق لبيانات المنتجات بتنسيق JSON من صفحات بيانات المنتجات في 1-800Flowers.com

عندما ينقر المستخدم على أحد العناصر، يمكن الحصول على بيانات JSON المرتبطة به من ذاكرة التخزين المؤقت بدون الحاجة إلى الانتقال إلى الشبكة، ما يجعل عملية التنقّل أسرع.

استخدام Workbox

توفّر Workbox طريقة سهلة لإرسال الرسائل إلى مشغّل الخدمات، من خلال حزمة workbox-window، وهي مجموعة من الوحدات المخصّصة للعمل في سياق النوافذ. وهي مكملة لحِزم Workbox الأخرى التي يتم تشغيلها في الخدمة العاملة.

للتواصل مع الصفحة من خلال مشغّل الخدمة، عليك أولاً الحصول على إشارة إلى عنصر Workbox تشير إلى مشغّل الخدمة المسجَّل:

const wb = new Workbox('/sw.js');
wb.register();

يمكنك بعد ذلك إرسال الرسالة مباشرةً بشكل صريح، بدون الحاجة إلى الحصول على التسجيل أو التحقّق من التفعيل أو التفكير في واجهة برمجة التطبيقات الأساسية للتواصل:

wb.messageSW({"type": "PREFETCH", "payload": {"urls": ["/data1.json", "data2.json"]}}); });

ينفذ عامل الخدمة معالِج message للاستماع إلى هذه الرسائل. يمكن أن يعرض الإجراء استجابة اختيارية، ولكن ليس ضروريًا في الحالات التالية:

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PREFETCH') {
    // do something
  }
});

استخدام واجهات برمجة تطبيقات المتصفّح

إذا لم تكن مكتبة Workbox كافية لتلبية احتياجاتك، إليك كيفية تنفيذ تواصل النافذة مع الخدمة العمل باستخدام واجهات برمجة تطبيقات المتصفّح.

يمكن استخدام postMessage API لإنشاء آلية تواصل أحادية الاتجاه من الصفحة إلى مشغّل الخدمة.

تستدعي الصفحة postMessage() في واجهة مشغّل الخدمة:

navigator.serviceWorker.controller.postMessage({
  type: 'MSG_ID',
  payload: 'some data to perform the task',
});

ينفِّذ worker الخدمة معالِج message لتلقّي هذه الرسائل.

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === MSG_ID) {
    // do something
  }
});

لا تكون السمة {type : 'MSG_ID'} مطلوبة تمامًا، ولكنها طريقة واحدة للسماح للصفحة بشدَّدأنواع مختلفة من التعليمات إلى مشغّل الخدمات (أي "لتحميل المحتوى مسبقًا" مقابل "محو ملف التخزين"). يمكن أن يتفرع العامل في الخدمة إلى مسارات تنفيذ مختلفة استنادًا إلى هذا الإعداد.

إذا كانت العملية ناجحة، سيتمكّن المستخدم من الاستفادة منها، ولكن إذا لم تكن كذلك، لن تؤدي إلى تغيير مسار المستخدم الرئيسي. على سبيل المثال، عندما يحاول 1-800-Flowers.com تخزين المحتوى في ذاكرة التخزين المؤقت، لن تحتاج الصفحة إلى معرفة ما إذا كان مشغّل الخدمة قد نجح أم لا. وفي حال توفّر هذا الخيار، سيستفيد المستخدم من تجربة تنقل أسرع. وإذا لم يحدث ذلك، يجب توجيه الصفحة إلى الصفحة الجديدة. سيستغرق الأمر بعض الوقت.

مثال بسيط على الترجيع المُسبَق

من أكثر التطبيقات شيوعًا لاستخدام التخزين المؤقت الضروري هو الجلب المسبق، وهو ما يعني جلب الموارد لعنوان URL معيّن، قبل انتقال المستخدم إليه، وذلك لتسريع عملية التنقل.

هناك طرق مختلفة لتنفيذ الجلب المُسبَق في المواقع الإلكترونية:

بالنسبة إلى سيناريوهات التحميل المُسبَق البسيطة نسبيًا، مثل التحميل المُسبَق للمستندات أو مواد عرض معيّنة (JavaScript و CSS وما إلى ذلك)، تُعدّ هذه الأساليب هي النهج الأفضل.

إذا كان مطلوبًا استخدام منطق إضافي، على سبيل المثال، تحليل مورد التخزين المُسبَق (ملف JSON أو صفحة) لجل جلب عناوين URL الداخلية، من الأفضل تفويض هذه المهمة بالكامل إلى عامل الخدمة.

ويحصل تفويض عامل الخدمة على هذه الأنواع من العمليات على المزايا التالية:

  • تفريغ الأحمال الكبيرة الناتجة عن الجلب والمعالجة بعد الجلب (وسيتم طرحه لاحقًا) في سلسلة محادثات ثانوية. وبذلك، يتم تحرير سلسلة المهام الرئيسية لمعالجة مهمات مهمة أكثر، مثل الاستجابة لتفاعلات المستخدمين.
  • السماح لعدة عملاء (مثل علامات التبويب) بإعادة استخدام وظيفة شائعة، وحتى استدعاء الخدمة في الوقت نفسه بدون حظر سلسلة المحادثات الرئيسية

ميزة "التحميل المُسبَق" لصفحات تفاصيل المنتجات

استخدِم postMessage() أولاً على واجهة مشغّل الخدمات وأدخِل مصفوفة من عناوين URL لتخزينها مؤقتًا:

navigator.serviceWorker.controller.postMessage({
  type: 'PREFETCH',
  payload: {
    urls: [
      'www.exmaple.com/apis/data_1.json',
      'www.exmaple.com/apis/data_2.json',
    ],
  },
});

في الخدمة العاملة، نفِّذ معالِج message لتلقّي الرسائل المُرسَلة من أي علامة تبويب نشطة ومعالجتها:

addEventListener('message', (event) => {
  let data = event.data;
  if (data && data.type === 'PREFETCH') {
    let urls = data.payload.urls;
    for (let i in urls) {
      fetchAsync(urls[i]);
    }
  }
});

في التعليمة البرمجية السابقة، قدّمنا دالة مساعدة صغيرة تُسمى fetchAsync() للتكرار في صفيف عناوين URL وإصدار طلب استرجاع لكل منها:

async function fetchAsync(url) {
  // await response of fetch call
  let prefetched = await fetch(url);
  // (optionally) cache resources in the service worker storage
}

وعند الحصول على الاستجابة، يمكنك الاعتماد على عناوين التخزين المؤقت للمورد. في كثير من الحالات، ومع ذلك، لا يتم تخزين الموارد في ذاكرة التخزين المؤقت، مثل صفحات تفاصيل المنتجات (يعني ذلك أنّها تحتوي على عنوان Cache-controlno-cache). في مثل هذه الحالات، يمكنك إلغاء هذا السلوك من خلال تخزين المورد الذي تم استرجاعه في ذاكرة التخزين المؤقت لخدمة Worker. وتمثل هذه الميزة فائدة إضافية تتمثل في السماح بعرض الملف في سيناريوهات وضع عدم الاتصال.

تنسيقات أخرى غير بيانات JSON

بعد استرجاع بيانات JSON من نقطة نهاية الخادم، غالبًا ما تحتوي على عناوين URL الأخرى التي تستحق أيضًا الجلب المسبق، مثل صورة أو بيانات نقطة نهاية أخرى مرتبطة ببيانات المستوى الأول هذه.

لنفترض أنّ بيانات JSON التي تم عرضها في مثالنا هي معلومات موقع إلكتروني للتسوّق في البقالة:

{
  "productName": "banana",
  "productPic": "https://cdn.example.com/product_images/banana.jpeg",
  "unitPrice": "1.99"
 }

عدِّل رمز fetchAsync() لتكرار قائمة المنتجات وتخزين الصورة الرئيسية لكل منتج في ذاكرة التخزين المؤقت:

async function fetchAsync(url, postProcess) {
  // await response of fetch call
  let prefetched = await fetch(url);

  //(optionally) cache resource in the service worker cache

  // carry out the post fetch process if supplied
  if (postProcess) {
    await postProcess(prefetched);
  }
}

async function postProcess(prefetched) {
  let productJson = await prefetched.json();
  if (productJson && productJson.product_pic) {
    fetchAsync(productJson.product_pic);
  }
}

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

الخاتمة

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

لمزيد من أنماط تواصل الخدمة مع الصفحة، اطّلِع على:

  • نشر التحديثات: استدعاء الصفحة من الخدمة العاملة لإعلام العميل بالتحديثات المهمة (مثل توفّر إصدار جديد من تطبيق الويب).
  • التواصل في الاتجاهين: تفويض مهمة إلى عامل خدمة (مثل عملية تنزيل كبيرة) وإبقاء الصفحة على اطّلاع بالتقدّم المحرز