Cache API: راهنمای سریع

با نحوه استفاده از Cache API برای در دسترس قرار دادن داده های برنامه به صورت آفلاین آشنا شوید.

Cache API سیستمی است برای ذخیره و بازیابی درخواست های شبکه و پاسخ های مربوط به آنها. اینها ممکن است درخواست‌ها و پاسخ‌های منظمی باشند که در طول اجرای برنامه شما ایجاد می‌شوند، یا می‌توانند صرفاً به منظور ذخیره داده‌ها برای استفاده بعدی ایجاد شوند.

Cache API برای فعال کردن سرویس‌دهندگان درخواست‌های شبکه ایجاد شد تا بتوانند بدون در نظر گرفتن سرعت یا در دسترس بودن شبکه، پاسخ‌های سریع ارائه دهند. با این حال، API همچنین می تواند به عنوان یک مکانیسم ذخیره سازی عمومی استفاده شود.

کجا موجود است؟

Cache API در همه مرورگرهای مدرن موجود است. از طریق ویژگی caches جهانی در معرض دید قرار می گیرد، بنابراین می توانید وجود API را با یک تشخیص ویژگی ساده آزمایش کنید:

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 ها ( 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 انواع مختلفی از داده ها را می پذیرد، از جمله BlobArrayBuffer 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 ظاهر شد.