واجهة برمجة تطبيقات ذاكرة التخزين المؤقت: دليل سريع

تعرَّف على كيفية استخدام Cache API لإتاحة بيانات تطبيقك بلا اتصال بالإنترنت.

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

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

أماكن توفّر المنصة

وتتوفر واجهة Cache API في جميع المتصفحات الحديثة. يتم عرض واجهة برمجة التطبيقات هذه من خلال السمة caches العامة، ما يتيح لك اختبار توفُّر واجهة برمجة التطبيقات من خلال اكتشاف ميزة بسيطة:

const cacheAvailable = 'caches' in self;

دعم المتصفح

  • 40
  • 16
  • 41
  • 11.1

المصدر

يمكن الوصول إلى Cache API من نافذة أو iframe أو عامل أو مشغِّل خدمات.

المعلومات التي يمكن تخزينها

وتخزِّن عمليات التخزين المؤقّت فقط أزواج العنصرَين Request وResponse التي تمثّل طلبات واستجابات HTTP على التوالي. ومع ذلك، يمكن أن تحتوي الطلبات والاستجابات على أي نوع من البيانات التي يمكن نقلها عبر HTTP.

ما مقدار البيانات التي يمكن تخزينها؟

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

إنشاء ذاكرة تخزين مؤقت وفتحها

لفتح ذاكرة تخزين مؤقت، استخدِم الطريقة caches.open(name) مع إدخال اسم ذاكرة التخزين المؤقت كمعلّمة واحدة. في حالة عدم وجود ذاكرة التخزين المؤقت المسماة، فسيتم إنشاؤها. تعرض هذه الطريقة دالة Promise التي يتم حلها مع الكائن Cache.

const cache = await caches.open('my-cache');
// do something with cache...

جارٍ الإضافة إلى ذاكرة تخزين مؤقت

هناك ثلاث طرق لإضافة عنصر إلى ذاكرة تخزين مؤقت - add وaddAll وput. تعرض الطرق الثلاث Promise.

cache.add

أَوَّلًا، فِيهْ cache.add(). يأخذ معلَمة واحدة، إما Request أو عنوان URL (string). ويُرسل طلبًا إلى الشبكة ويخزّن الاستجابة في ذاكرة التخزين المؤقت. إذا تعذّر الجلب أو إذا لم يكن رمز الحالة للاستجابة ضمن النطاق 200، فلن يتم تخزين أي شيء وسيتم رفض Promise. يُرجى العِلم أنّه لا يمكن تخزين الطلبات من مصادر متعددة التي لا تكون في وضع CORS لأنّها تعرض status من 0. لا يمكن تخزين هذه الطلبات إلا مع put.

// Retreive data.json from the server and store the response.
cache.add(new Request('/data.json'));

// Retreive data.json from the server and store the response.
cache.add('/data.json');

cache.addAll

الْلِّي بَعْدْ كِدَهْ، cache.addAll(). وهي تعمل بشكل مشابه لـ add()، ولكنها تأخذ مصفوفة من كائنات Request أو عناوين URL (strings). ويعمل ذلك بشكل مشابه لطلب cache.add لكل طلب فردي، باستثناء أنّ Promise يرفض إذا لم يتم تخزين أي طلب فردي في ذاكرة التخزين المؤقت.

const urls = ['/weather/today.json', '/weather/tomorrow.json'];
cache.addAll(urls);

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

cache.put

وأخيرًا، هناك cache.put()، الذي يتيح لك تخزين رد من الشبكة أو إنشاء Response خاص بك وتخزينه. يتطلب الأمر معاملين. وقد يكون النوع الأول إما كائن Request أو عنوان URL (string). ويجب أن يكون النوع الثاني Response، إما من الشبكة أو من إنشاء الرمز.

// Retrieve data.json from the server and store the response.
cache.put('/data.json');

// Create a new entry for test.json and store the newly created response.
cache.put('/test.json', new Response('{"foo": "bar"}'));

// Retrieve data.json from the 3rd party site and store the response.
cache.put('https://example.com/data.json');

إنّ طريقة put() أكثر تساهلاً من add() أو addAll() وستسمح لك بتخزين الاستجابات غير المستندة إلى سياسة مشاركة الموارد المتعددة المصادر (CORS) أو الاستجابات الأخرى التي لا يكون فيها رمز حالة الاستجابة ضمن النطاق 200. وسيحل محل أي ردود سابقة لنفس الطلب.

إنشاء عناصر "الطلبات"

يمكنك إنشاء الكائن Request باستخدام عنوان URL للعنصر الذي يتم تخزينه:

const request = new Request('/my-data-store/item-id');

التعامل مع عناصر الاستجابة

تقبل الدالة الإنشائية للكائن Response العديد من أنواع البيانات، بما في ذلك كائنات Blob وArrayBuffer وFormData والسلاسل.

const imageBlob = new Blob([data], {type: 'image/jpeg'});
const imageResponse = new Response(imageBlob);
const stringResponse = new Response('Hello world');

يمكنك ضبط نوع MIME لـ Response من خلال ضبط العنوان المناسب.

  const options = {
    headers: {
      'Content-Type': 'application/json'
    }
  }
  const jsonResponse = new Response('{}', options);

إذا استعدت Response وأردت الوصول إلى نصه، يمكنك اتّباع عدة طرق مساعِدة. يعرض كل منها نوع Promise الذي تتم مطابقته بقيمة من نوع مختلف.

الطريقة الوصف
arrayBuffer تعرض عنصر ArrayBuffer يحتوي على النص الأساسي، بشكل متسلسل إلى بايت.
blob تعرض Blob. إذا تم إنشاء السمة Response باستخدام Blob، سيكون النوع نفسه من السمة Blob الجديدة هذه. وبخلاف ذلك، يتم استخدام Content-Type من Response.
text يفسّر وحدات بايت النص كسلسلة مرمّزة بترميز UTF-8.
json يفسّر وحدات بايت النص كسلسلة مرمّزة بترميز UTF-8، ثم يحاول تحليله على هيئة JSON. تعرض الكائن الناتج أو تطرح TypeError إذا تعذّر تحليل السلسلة على هيئة JSON.
formData يفسّر وحدات بايت النص الأساسي كنموذج HTML، مرمّزًا إما على هيئة multipart/form-data أو application/x-www-form-urlencoded. تعرض كائن FormData أو تطرح TypeError إذا تعذّر تحليل البيانات.
body تعرض هذه الدالة ReadableStream لبيانات النص الأساسي.

على سبيل المثال:

const response = new Response('Hello world');
const buffer = await response.arrayBuffer();
console.log(new Uint8Array(buffer));
// Uint8Array(11) [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]

الاسترداد من ذاكرة تخزين مؤقت

للعثور على عنصر في ذاكرة التخزين المؤقت، يمكنك استخدام الطريقة match.

const response = await cache.match(request);
console.log(request, response);

إذا كانت السمة request عبارة عن سلسلة، يحوّلها المتصفّح إلى قيمة Request من خلال استدعاء new Request(request). تعرض الدالة Promise الذي يؤدي إلى Response في حال العثور على إدخال مطابق، أو undefined بخلاف ذلك.

لتحديد ما إذا كان حقلا Requests متطابقَين، يستخدم المتصفّح أكثر من عنوان URL فقط. يُعتبر الطلبان مختلفَين إذا كان لهما سلاسل طلب بحث مختلفة، أو عناوين Vary، أو طرق HTTP (GET أو POST أو PUT أو غير ذلك).

يمكنك تجاهل بعض هذه الأشياء أو جميعها بتمرير كائن خيارات كمعلمة ثانية.

const options = {
  ignoreSearch: true,
  ignoreMethod: true,
  ignoreVary: true
};

const response = await cache.match(request, options);
// do something with the response

وفي حال تطابق أكثر من طلب مخزَّن مؤقتًا، يتم عرض الطلب الذي تم إنشاؤه أولاً. إذا أردت استرداد جميع الردود المطابقة، يمكنك استخدام cache.matchAll().

const options = {
  ignoreSearch: true,
  ignoreMethod: true,
  ignoreVary: true
};

const responses = await cache.matchAll(request, options);
console.log(`There are ${responses.length} matching responses.`);

كاختصار، يمكنك البحث في كل ذاكرات التخزين المؤقت في آنٍ واحد باستخدام caches.match() بدلاً من طلب cache.match() لكل ذاكرة تخزين مؤقت.

جارٍ البحث

لا توفّر Cache API طريقة للبحث عن الطلبات أو الردود باستثناء الإدخالات المطابقة لعنصر Response. مع ذلك، يمكنك تنفيذ بحثك الخاص باستخدام الفلترة أو إنشاء فهرس.

الفلترة

يمكنك تكرار البحث عن طريق إضافة النتائج المكررة على جميع الإدخالات والتصفية للوصول إلى الإدخالات المطلوبة. لنفترض أنك تريد العثور على جميع العناصر التي تحتوي على عناوين URL تنتهي بـ .png.

async function findImages() {
  // Get a list of all of the caches for this origin
  const cacheNames = await caches.keys();
  const result = [];

  for (const name of cacheNames) {
    // Open the cache
    const cache = await caches.open(name);

    // Get a list of entries. Each item is a Request object
    for (const request of await cache.keys()) {
      // If the request URL matches, add the response to the result
      if (request.url.endsWith('.png')) {
        result.push(await cache.match(request));
      }
    }
  }

  return result;
}

بهذه الطريقة، يمكنك استخدام أي سمة من الكائنات Request وResponse لفلترة الإدخالات. لاحظ أن هذه العملية بطيئة إذا بحثت عبر مجموعات كبيرة من البيانات.

إنشاء فهرس

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

إذا خزّنت عنوان URL للسمة Request مع السمات القابلة للبحث، يمكنك بسهولة استرداد إدخال ذاكرة التخزين المؤقت الصحيح بعد إجراء البحث.

حذف عنصر

لحذف عنصر من ذاكرة تخزين مؤقت:

cache.delete(request);

حيث يمكن أن يكون الطلب Request أو سلسلة عنوان URL. تستخدم هذه الطريقة أيضًا كائن الخيارات نفسه الموجود في cache.match، ما يسمح لك بحذف عدة أزواج من Request/Response لعنوان URL نفسه.

cache.delete('/example/file.txt', {ignoreVary: true, ignoreSearch: true});

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

لحذف ذاكرة تخزين مؤقت، اتصِل بالرقم caches.delete(name). تعرض هذه الدالة علامة Promise التي يتم ضبطها على true في حال كانت ذاكرة التخزين المؤقت متوفّرة وتم حذفها، أو false بخلاف ذلك.

شكرًا

بفضل Mat Scales الذي كتب النسخة الأصلية من هذه المقالة، والتي ظهرت لأول مرة على WebFundamentals.