من الجوانب الرئيسية لتطبيقات الويب التقدمية أنها موثوقة؛ يمكنهم تحميل الأصول بسرعة، مما يحافظ على تفاعل المستخدمين ويقدمون ملاحظاتهم على الفور، حتى في ظل ظروف الشبكة السيئة. كيف يمكن حدوث ذلك؟ بفضل حدث fetch
لعامل الخدمات
حدث الجلب
يتيح لنا حدث fetch
اعتراض كل طلب شبكة يُرسله تطبيق الويب التقدّمي (PWA) في نطاق مشغّل الخدمات، لكل من الطلبات ذات المصدر نفسه والطلبات الواردة من عدّة مصادر. بالإضافة إلى طلبات التنقّل ومواد العرض، يسمح الجلب من مشغّل الخدمات المثبَّت بعرض زيارات الصفحة بعد التحميل الأول للموقع بدون مكالمات الشبكة.
يتلقّى معالج fetch
جميع الطلبات من التطبيق، بما في ذلك عناوين URL وعناوين HTTP، ويسمح لمطوِّر التطبيق بتحديد كيفية معالجتها.
يمكن لعامل الخدمة إعادة توجيه طلب إلى الشبكة أو الرد باستخدام استجابة مخزّنة مؤقتًا من قبل أو إنشاء استجابة جديدة. القرار بيدك لاختيار الصوت الذي يناسبك. إليك مثال بسيط:
self.addEventListener("fetch", event => {
console.log(`URL requested: ${event.request.url}`);
});
الاستجابة لطلب
عندما يأتي طلب إلى عامل الخدمات لديك، هناك أمران يمكنك القيام بهما: يمكنك تجاهلها، مما يتيح لها الوصول إلى الشبكة، أو يمكنك الاستجابة لها. ويحدّد الرد على الطلبات من داخل مشغّل الخدمات كيفية اختيار البيانات وكيفية عرضها في تطبيق الويب التقدّمي (PWA)، حتى عندما يكون المستخدم غير متصل بالإنترنت.
للردّ على طلب وارد، يمكنك الاتصال بـ "event.respondWith()
" من داخل معالِج أحداث "fetch
"، على النحو التالي:
// fetch event handler in your service worker file
self.addEventListener("fetch", event => {
const response = .... // a response or a Promise of response
event.respondWith(response);
});
عليك استدعاء respondWith()
بشكل متزامن ويجب عرض كائن Response. ولكن لا يمكنك استدعاء الدالة respondWith()
بعد انتهاء معالج أحداث الجلب، كما هو الحال في مكالمة غير متزامنة. إذا كنت بحاجة إلى انتظار الردّ الكامل، يمكنك إرسال وعد إلى "respondWith()
" يتمّ حلّه من خلال الردّ.
إنشاء الردود
وبفضل واجهة برمجة تطبيقات الجلب، يمكنك إنشاء استجابات HTTP في رمز JavaScript، ويمكن تخزين هذه الاستجابات مؤقتًا باستخدام واجهة برمجة تطبيقات مساحة تخزين ذاكرة التخزين المؤقت وعرضها كما لو كانت واردة من خادم ويب.
لإنشاء ردّ، يمكنك إنشاء عنصر Response
جديد، مع ضبط نصه وخياراته، مثل الحالة والعناوين:
const simpleResponse = new Response("Body of the HTTP response");
const options = {
status: 200,
headers: {
'Content-type': 'text/html'
}
};
const htmlResponse = new Response("<b>HTML</b> content", options)
الاستجابة من ذاكرة التخزين المؤقت
والآن بعد أن عرفت كيفية عرض استجابات HTTP من مشغّل الخدمات، حان الوقت لاستخدام واجهة التخزين المؤقت لتخزين مواد العرض على الجهاز.
يمكنك استخدام واجهة برمجة التطبيقات Cache Storage API للتحقّق مما إذا كان الطلب الذي تم استلامه من تطبيق الويب التقدّمي (PWA) متاحًا في ذاكرة التخزين المؤقت، وإذا كان كذلك، يمكنك الردّ على respondWith()
باستخدامه.
لإجراء ذلك، عليك أولاً البحث داخل ذاكرة التخزين المؤقت. إنّ الدالة match()
المتوفّرة في واجهة caches
ذات المستوى الأعلى تبحث في كل المتاجر في المصدر أو في عنصر واحد مفتوح لذاكرة التخزين المؤقت.
تتلقّى الدالة match()
طلب HTTP أو عنوان URL كوسيطة، وتعرض وعدًا يتم حله مع الاستجابة المرتبطة بالمفتاح المقابل.
// Global search on all caches in the current origin
caches.match(urlOrRequest).then(response => {
console.log(response ? response : "It's not in the cache");
});
// Cache-specific search
caches.open("pwa-assets").then(cache => {
cache.match(urlOrRequest).then(response => {
console.log(response ? response : "It's not in the cache");
});
});
استراتيجيات التخزين المؤقت
عرض الملفات من ذاكرة التخزين المؤقت للمتصفّح فقط لا يناسب جميع حالات الاستخدام. على سبيل المثال، يمكن للمستخدم أو المتصفح إزالة ذاكرة التخزين المؤقت. لهذا السبب، عليك تحديد استراتيجياتك الخاصة لإرسال مواد العرض لتطبيق الويب التقدّمي (PWA).
لا تقتصر على استراتيجية واحدة للتخزين المؤقت. يمكنك تحديد أنماط مختلفة لأنماط عناوين URL المختلفة. على سبيل المثال، يمكنك وضع استراتيجية واحدة للحدّ الأدنى من مواد عرض واجهة المستخدم، وأخرى لطلبات البيانات من واجهة برمجة التطبيقات، واستراتيجية ثالثة لعناوين URL للصور والبيانات.
لإجراء ذلك، اقرأ event.request.url
في ServiceWorkerGlobalScope.onfetch
وحللها من خلال التعبيرات العادية أو نمط عنوان URL. (في وقت كتابة هذه المقالة، لم يكن نمط عنوان URL متاحًا على جميع الأنظمة الأساسية).
ومن أكثر الاستراتيجيات شيوعًا:
- ذاكرة التخزين المؤقت أولاً
- يبحث عن استجابة مخزّنة مؤقتًا أولاً ويعود إلى الشبكة في حال عدم العثور على ردّ.
- الشبكة أولاً
- تطلب ردًا من الشبكة أولاً وإذا لم يتم عرض أي رد، يتم البحث عن الاستجابة في ذاكرة التخزين المؤقت.
- قديم أثناء إعادة التحقّق
- يعرض هذا الخيار ردًا من ذاكرة التخزين المؤقت، بينما يتم طلب الإصدار الأحدث في الخلفية ويحفظه في ذاكرة التخزين المؤقت لاستخدامه في المرة التالية التي يتم فيها طلب مادة العرض.
- الشبكة فقط
- يتم دائمًا الرد على الرسائل من الشبكة أو تتضمّن أخطاءً. ولا تتم الاستعانة بذاكرة التخزين المؤقت مطلقًا.
- ذاكرة التخزين المؤقت فقط
- يمكنك دائمًا الردّ على الرسائل من ذاكرة التخزين المؤقت أو إظهار أخطاء. لن يتم استشارة الشبكة مطلقًا. يجب إضافة مواد العرض التي سيتم عرضها باستخدام هذه الاستراتيجية إلى ذاكرة التخزين المؤقت قبل أن يتم طلبها.
ذاكرة التخزين المؤقت أولاً
باستخدام هذه الاستراتيجية، يبحث عامل الخدمة عن الطلب المطابق في ذاكرة التخزين المؤقت ويعرض الاستجابة المقابلة إذا كان هذا الملف مخزَّنًا مؤقتًا. وبخلاف ذلك، يتم استرداد الاستجابة من الشبكة (اختياريًا، من خلال تعديل ذاكرة التخزين المؤقت للمكالمات المستقبلية). إذا لم تكن هناك استجابة ذاكرة التخزين المؤقت أو استجابة الشبكة، سيظهر خطأ في الطلب. وبما أنّ عرض مواد العرض بدون الانتقال إلى الشبكة يميل إلى أن يكون أسرع، تعطي هذه الاستراتيجية الأولوية للأداء على الحداثة.
self.addEventListener("fetch", event => {
event.respondWith(
caches.match(event.request)
.then(cachedResponse => {
// It can update the cache to serve updated content on the next request
return cachedResponse || fetch(event.request);
}
)
)
});
الشبكة أولاً
هذه الاستراتيجية هي نسخة مطابقة لاستراتيجية ذاكرة التخزين المؤقت أولاً، يتحقق مما إذا كان يمكن تنفيذ الطلب من الشبكة، وإذا لم يكن ممكنًا، يحاول استرداده من ذاكرة التخزين المؤقت. مثل ذاكرة التخزين المؤقت أولاً. إذا لم تكن هناك استجابة الشبكة أو استجابة ذاكرة التخزين المؤقت، فسوف يحدث خطأ في الطلب. عادةً ما يكون الحصول على الاستجابة من الشبكة أبطأ من الحصول عليها من ذاكرة التخزين المؤقت، وتعطي هذه الإستراتيجية الأولوية للمحتوى المعدَّل بدلاً من الأداء.
self.addEventListener("fetch", event => {
event.respondWith(
fetch(event.request)
.catch(error => {
return caches.match(event.request) ;
})
);
});
قديمة أثناء إعادة التحقّق
تعرض الاستراتيجية القديمة أثناء إعادة التحقّق من استجابة ذاكرة التخزين المؤقت على الفور، ثم تبحث في الشبكة عن تحديث، وتستبدل الاستجابة المخزَّنة مؤقتًا في حال العثور على تحديث. دائمًا ما تطلب هذه الاستراتيجية طلب الشبكة، لأنّه حتى في حال العثور على مورد مخزَّن مؤقتًا، ستحاول تحديث البيانات المخزّنة في ذاكرة التخزين المؤقت بما تم استلامه من الشبكة لاستخدام النسخة المعدّلة في الطلب التالي. ولهذا السبب، توفّر لك هذه الاستراتيجية طريقة للاستفادة من العرض السريع لاستراتيجية ذاكرة التخزين المؤقت أولاً وتعديل ذاكرة التخزين المؤقت في الخلفية.
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cachedResponse => {
const networkFetch = fetch(event.request).then(response => {
// update the cache with a clone of the network response
const responseClone = response.clone()
caches.open(url.searchParams.get('name')).then(cache => {
cache.put(event.request, responseClone)
})
return response
}).catch(function (reason) {
console.error('ServiceWorker fetch failed: ', reason)
})
// prioritize cached response over network
return cachedResponse || networkFetch
}
)
)
})
الشبكة فقط
تتشابه استراتيجية الشبكة فقط مع سلوك المتصفحات بدون عامل خدمة أو واجهة برمجة تطبيقات Cache Storage. ولن تعرض الطلبات مصدرًا إلا إذا كان من الممكن جلبه من الشبكة. وغالبًا ما يكون ذلك مفيدًا للموارد مثل طلبات البيانات من واجهة برمجة التطبيقات على الإنترنت فقط.
ذاكرة التخزين المؤقت فقط
تضمن استراتيجية ذاكرة التخزين المؤقت فقط عدم انتقال الطلبات إلى الشبكة أبدًا. يتم الرد على جميع الطلبات الواردة بعنصر ذاكرة تخزين مؤقت مملوء مسبقًا. يستخدم الرمز التالي معالِج أحداث fetch
مع الطريقة match
الخاصة بمساحة تخزين ذاكرة التخزين المؤقت للاستجابة إلى ذاكرة التخزين المؤقت فقط:
self.addEventListener("fetch", event => {
event.respondWith(caches.match(event.request));
});
الاستراتيجيات المخصّصة
في حين أن ما ورد أعلاه يمثل إستراتيجيات شائعة للتخزين المؤقت، فأنت مسؤول عن مشغّل الخدمات وكيفية التعامل مع الطلبات. إذا لم ينجح أي من هذه الخطوات في تلبية احتياجاتك، يمكنك إنشاء نماذج خاصة بك.
ويمكنك مثلاً استخدام استراتيجية الشبكة أولاً مع ضبط مهلة لمنح الأولوية للمحتوى المعدَّل، شرط أن تظهر الاستجابة ضمن الحدّ الأدنى الذي حدّدته. يمكنك أيضًا دمج استجابة مخزّنة مؤقتًا مع استجابة الشبكة وإنشاء استجابة معقدة من عامل الخدمة.
جارٍ تعديل مواد العرض
قد يمثّل تحديث مواد العرض المخزّنة مؤقتًا في تطبيق الويب التقدّمي تحديًا كبيرًا. وهي إحدى الطرق لإجراء ذلك، بالرغم من أنّها قديمة مع إعادة التحقّق من صحتها، ولكنها ليست الطريقة الوحيدة. ستتعرّف في الفصل من التعديلات على أساليب مختلفة للحفاظ على حداثة محتوى تطبيقك ومواد العرض فيه.