قد تحتاج بعض المواقع الإلكترونية إلى التواصل مع عامل الخدمة بدون الحاجة إلى إعلامها بالنتيجة. وإليك بعض الأمثلة:
- تُرسِل الصفحة إلى مشغّل الخدمة قائمة بعناوين URL لتحميلها مسبقًا، بحيث تكون الموارد الفرعية للمستند أو الصفحة متاحة في ذاكرة التخزين المؤقت عندما ينقر المستخدم على رابط، ما يجعل التنقّل التالي أسرع بكثير.
- تطلب الصفحة من مشغّل الخدمة استرداد مجموعة من أهم المقالات وتخزينها مؤقتًا لكي تكون متاحة بلا إنترنت.
إنّ تفويض هذه الأنواع من المهام غير المُهمّة إلى الخدمة العاملة يُحقّق ميزة تحرير السلسلة المُهمّة من أجل معالجة المهام الأكثر إلحاحًا بشكلٍ أفضل، مثل الاستجابة لتفاعلات المستخدمين.
في هذا الدليل، سنستكشف كيفية تنفيذ أسلوب تواصل أحادي الاتجاه من الصفحة إلى عامل الخدمة باستخدام واجهات برمجة تطبيقات المتصفّح العادية ومكتبة Workbox. سنُطلق على هذه الأنواع من حالات الاستخدام اسم التخزين المؤقت الإلزامي.
طلب الإنتاج
نفَّذ موقع 1-800-Flowers.com التخزين المؤقت الإلزامي (التحميل المُسبَق) باستخدام مهام الخدمة من خلال
postMessage()
لتحميل المشتريات الأكثر رواجًا في صفحات الفئات مُسبَقًا لتسريع التنقّل اللاحق إلى صفحات تفاصيل المنتجات.
ويستخدمون نهجًا مختلطًا لتحديد العناصر التي سيتم تحميلها مسبقًا:
- في وقت تحميل الصفحة، يطلبون من عامل الخدمة استرداد بيانات JSON الخاصة بأكبر 9 عناصر، وإضافة عناصر الاستجابة الناتجة إلى ذاكرة التخزين المؤقت.
- بالنسبة إلى العناصر المتبقية، يتم الاستماع إلى الحدث
mouseover
، بحيث يمكن للمستخدِم عند تحريك المؤشر فوق عنصر أن يشغّل عملية جلب للمورد عند الطلب.
وتستخدم Cache API لتخزين استجابات JSON:
عندما ينقر المستخدم على عنصر، يمكن الحصول على بيانات 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 معيّن قبل أن ينتقل إليه المستخدم، وذلك لتسريع عملية التنقّل.
هناك طرق مختلفة لتنفيذ ميزة "التحميل المُسبَق" في المواقع الإلكترونية:
- استخدام علامات جلب الموارد مسبقًا للرابط في الصفحات: يتم الاحتفاظ بالموارد في
ذاكرة التخزين المؤقت للمتصفّح لمدة خمس دقائق، وبعد ذلك يتم تطبيق قواعد
Cache-Control
العادية للمورد. - استكمال التقنية السابقة باستخدام استراتيجية تخزين مؤقت أثناء التشغيل في worker الخدمة لزيادة مدة صلاحية موارد التحميل المُسبَق إلى ما بعد هذا الحدّ
بالنسبة إلى سيناريوهات التحميل المُسبَق البسيطة نسبيًا، مثل التحميل المُسبَق للمستندات أو مواد عرض معيّنة (JavaScript و CSS وما إلى ذلك)، تُعدّ هذه الأساليب هي النهج الأفضل.
إذا كان مطلوبًا استخدام منطق إضافي، على سبيل المثال، تحليل مورد التخزين المُسبَق (ملف JSON أو صفحة) لجل جلب عناوين URL الداخلية، من الأفضل تفويض هذه المهمة بالكامل إلى عامل الخدمة.
تعود عليك مزايا التالية عند تفويض هذه الأنواع من العمليات إلى الخدمة العاملة:
- تخفيف الأعباء الثقيلة لعمليات الجلب والمعالجة بعد الجلب (التي سيتمّ تقديمها لاحقًا) إلى سلسلة محادثات ثانوية وبذلك، يتم تحرير سلسلة المهام الرئيسية لمعالجة مهمات مهمة أكثر، مثل الاستجابة لتفاعلات المستخدمين.
- السماح لعدة عملاء (مثل علامات التبويب) بإعادة استخدام وظيفة شائعة، وحتى استدعاء الخدمة في الوقت نفسه بدون حظر سلسلة المحادثات الرئيسية
ميزة "التحميل المُسبَق" لصفحات تفاصيل المنتجات
استخدِم أولاً postMessage()
في
واجهة worker الخدمة وتمرير صفيف من عناوين 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-control
no-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. ولكن يكمن جمال استخدام مشغّل الخدمات في ميزة "التحميل المُسبَق" في أنّه يمكن أن يتعذّر عليه إكمال المهمة بدون أن يؤدي ذلك إلى عواقب مزعجة على الصفحة والخيط الرئيسي. يمكنك أيضًا استخدام منطق أكثر تفصيلاً في مرحلة المعالجة اللاحقة للمحتوى الذي تم جلبه مسبقًا، ما يجعله أكثر مرونة ومستقلًا عن البيانات التي تتم معالجتها. لا حدود تواجهك سوى السماء.
الخاتمة
في هذه المقالة، غطّينا حالة استخدام شائعة للتواصل الاتجاهي بين الصفحة وعامل الخدمة: التخزين المؤقت الإلزامي. إنّ الأمثلة التي تمت مناقشتها مخصّصة فقط لعرض طريقة واحدة ل استخدام هذا النمط، ويمكن تطبيق النهج نفسه على حالات الاستخدام الأخرى أيضًا، على سبيل المثال، تخزين أهم المقالات عند الطلب للاستهلاك بلا إنترنت ووضع الإشارات المرجعية وغير ذلك.
لمزيد من أنماط تواصل الخدمة مع الصفحة، يمكنك الاطّلاع على:
- نشر التحديثات: استدعاء الصفحة من الخدمة العاملة لإعلام العميل بالتحديثات المهمة (مثل توفّر إصدار جديد من تطبيق الويب).
- التواصل الثنائي الاتجاه: تفويض مهمة إلى عامل خدمة (مثل عملية تنزيل كبيرة) وإبقاء الصفحة على اطّلاع بالتقدّم المحرز