با نحوه استفاده از Cache API برای در دسترس قرار دادن داده های برنامه به صورت آفلاین آشنا شوید.
Cache API سیستمی است برای ذخیره و بازیابی درخواست های شبکه و پاسخ های مربوط به آنها. اینها ممکن است درخواستها و پاسخهای منظمی باشند که در طول اجرای برنامه شما ایجاد میشوند، یا میتوانند صرفاً به منظور ذخیره دادهها برای استفاده بعدی ایجاد شوند.
Cache API برای فعال کردن سرویسدهندگان درخواستهای شبکه ایجاد شد تا بتوانند بدون در نظر گرفتن سرعت یا در دسترس بودن شبکه، پاسخهای سریع ارائه دهند. با این حال، API همچنین می تواند به عنوان یک مکانیسم ذخیره سازی عمومی استفاده شود.
کجا موجود است؟
Cache API در همه مرورگرهای مدرن موجود است. از طریق ویژگی caches
جهانی در معرض دید قرار می گیرد، بنابراین می توانید وجود API را با یک تشخیص ویژگی ساده آزمایش کنید:
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
ها) را می گیرد. این کار به طور مشابه با فراخوانی cache.add
برای هر درخواست جداگانه عمل می کند، با این تفاوت که اگر هر درخواستی در حافظه پنهان ذخیره نشود، Promise
رد می کند.
const urls = ['/weather/today.json', '/weather/tomorrow.json'];
cache.addAll(urls);
در هر یک از این موارد، یک ورودی جدید هر ورودی منطبق بر موجود را بازنویسی می کند. این از همان قوانین تطبیق شرح داده شده در بخش بازیابی استفاده می کند.
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
سازنده شی Response
انواع مختلفی از داده ها را می پذیرد، از جمله Blob
s، ArrayBuffer
s، اشیاء 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 of the Response استفاده می شود. |
text | بایت های بدنه را به عنوان یک رشته رمزگذاری شده UTF-8 تفسیر می کند. |
json | بایت های بدنه را به عنوان یک رشته رمزگذاری شده UTF-8 تفسیر می کند، سپس سعی می کند آن را به عنوان JSON تجزیه کند. اگر رشته بهعنوان JSON قابل تجزیه نباشد، شیء بهدستآمده را برمیگرداند یا یک TypeError میدهد. |
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
یک رشته باشد، مرورگر با فراخوانی new Request(request)
آن را به یک Request
تبدیل می کند. این تابع یک Promise
برمیگرداند که در صورت یافتن ورودی منطبق یا undefined
، به یک Response
حل میشود.
برای تعیین اینکه آیا دو 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
ارائه نمیکند. با این حال، می توانید جستجوی خود را با استفاده از فیلتر کردن یا با ایجاد یک فهرست پیاده سازی کنید.
فیلتر کردن
یکی از راههای پیادهسازی جستجوی خود این است که همه ورودیها را تکرار کنید و به مواردی که میخواهید فیلتر کنید. فرض کنید میخواهید همه مواردی را پیدا کنید که نشانیهای اینترنتی با .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 ظاهر شد.