تعرَّف على كيفية استخدام Cache API لإتاحة بيانات تطبيقك بلا اتصال بالإنترنت.
cache API هي نظام لتخزين واسترداد طلبات الشبكة والردود المقابلة لها. وقد تكون هذه الطلبات واستجابات منتظمة تم إنشاؤها أثناء تشغيل التطبيق، أو قد يتم إنشاؤها فقط لغرض تخزين البيانات لاستخدامها لاحقًا.
تم إنشاء واجهة برمجة تطبيقات ذاكرة التخزين المؤقت لتمكين العاملين في الخدمة من تخزين طلبات الشبكة في ذاكرة التخزين المؤقت حتى يتمكنوا من تقديم ردود سريعة، بصرف النظر عن سرعة الشبكة أو مدى توفّرها. ومع ذلك، يمكن أيضًا استخدام واجهة برمجة التطبيقات كآلية تخزين عامة.
أماكن توفّر المنصة
تتوفر Cache API في جميع المتصفحات الحديثة. ويظهر هذا الترميز من خلال السمة caches
العالمية، ما يعني أنّه يمكنك اختبار توفُّر واجهة برمجة التطبيقات من خلال عملية بسيطة لرصد الميزات:
const cacheAvailable = 'caches' in self;
يمكن الوصول إلى 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 (string
s). وتشبه هذه العملية استدعاء 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
.
شكرًا
وبفضل "مات سكاليس" الذي كتب النسخة الأصلية من هذه المقالة، والتي ظهرت لأول مرة على منصة WebFundamentals.