جارٍ العرض

تتمثل أحد الجوانب الرئيسية لتطبيقات الويب التقدّمية في الموثوقية، إذ يمكنها تحميل الأصول بسرعة والحفاظ على تفاعل المستخدمين وتقديم الملاحظات على الفور، حتى في ظروف الشبكة السيئة. كيف يمكن ذلك؟ نشكرك على حدث "fetch" لمشغّل الخدمات.

حدث الجلب

التوافق مع المتصفح

  • 40
  • 17
  • 44
  • 11.1

المصدر

يتيح لنا حدث 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، ويمكن تخزين هذه الاستجابات مؤقتًا باستخدام واجهة برمجة التطبيقات Cache Storage API وعرضها كما لو كانت واردة من خادم ويب.

لإنشاء ردّ، يمكنك إنشاء عنصر 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 من أحد مشغّلي الخدمات، حان الوقت لاستخدام واجهة التخزين المؤقت لتخزين الأصول على الجهاز.

يمكنك استخدام واجهة برمجة التطبيقات لتخزين ذاكرة التخزين المؤقت للتحقّق مما إذا كان الطلب الذي تم استلامه من تطبيق الويب التقدّمي (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");
  });
});

استراتيجيات التخزين المؤقت

لا يناسب عرض الملفات فقط من ذاكرة التخزين المؤقت في المتصفّح كل حالات الاستخدام. على سبيل المثال، يمكن للمستخدم أو المتصفّح التخلص من ذاكرة التخزين المؤقت. لهذا السبب، عليك تحديد استراتيجياتك الخاصة لتقديم مواد العرض لتطبيقات الويب التقدّمية الخاصة بك. لست مقيَّدًا باستراتيجية واحدة للتخزين المؤقت. يمكنك تحديد أنماط مختلفة لأنماط عناوين 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);
     }
   )
  )
});

الشبكة أولاً

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

استراتيجية Network First

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
      }
    )
  )
})

الشبكة فقط

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

استراتيجية الشبكة فقط

ذاكرة التخزين المؤقت فقط

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

self.addEventListener("fetch", event => {
   event.respondWith(caches.match(event.request));
});

استراتيجية ذاكرة التخزين المؤقت فقط.

الاستراتيجيات المخصّصة

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

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

جارٍ تعديل مواد العرض

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

المراجِع