कैश एपीआई: एक छोटी सी गाइड

अपने ऐप्लिकेशन के डेटा को ऑफ़लाइन उपलब्ध कराने के लिए, कैश एपीआई इस्तेमाल करने का तरीका जानें.

Cache API, नेटवर्क के अनुरोधों और उनसे जुड़े रिस्पॉन्स को सेव और फिर से पाने का सिस्टम है. ये आपके ऐप्लिकेशन को चलाने के दौरान, सामान्य अनुरोध और जवाब हो सकते हैं. इसके अलावा, इन्हें सिर्फ़ बाद में इस्तेमाल करने के लिए डेटा सेव करने के मकसद से भी बनाया जा सकता है.

Cache API को इसलिए बनाया गया था, ताकि सेवा वर्कर नेटवर्क अनुरोधों को कैश मेमोरी में सेव कर सकें. इससे, नेटवर्क की स्पीड या उपलब्धता के बावजूद, तेज़ी से जवाब दिए जा सकते हैं. हालांकि, एपीआई का इस्तेमाल सामान्य स्टोरेज के तौर पर भी किया जा सकता है.

YouTube TV कहां उपलब्ध है?

Cache API, सभी मॉडर्न ब्राउज़र में उपलब्ध है. इसे ग्लोबल caches प्रॉपर्टी के ज़रिए एक्सपोज़ किया जाता है, ताकि किसी सुविधा का पता लगाने के लिए एपीआई की मौजूदगी की जांच की जा सके:

const cacheAvailable = 'caches' in self;

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 40.
  • Edge: 16.
  • Firefox: 41.
  • Safari: 11.1.

सोर्स

Cache API को किसी विंडो, iframe, वर्कर या सर्विस वर्कर से ऐक्सेस किया जा सकता है.

क्या-क्या सेव किया जा सकता है

कैश मेमोरी में सिर्फ़ Request और Response ऑब्जेक्ट के पेयर सेव किए जाते हैं. ये ऑब्जेक्ट, 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 या यूआरएल (string). यह नेटवर्क से अनुरोध करता है और रिस्पॉन्स को कैश मेमोरी में सेव करता है. अगर फ़ेच करने में कोई गड़बड़ी होती है या जवाब का स्टेटस कोड 200 की रेंज में नहीं होता है, तो कुछ भी सेव नहीं किया जाता और Promise अस्वीकार कर दिया जाता है. ध्यान दें कि क्रॉस-ऑरिजिन वाले ऐसे अनुरोध सेव नहीं किए जा सकते जो सीओआरएस मोड में नहीं हैं, क्योंकि वे 0 का status दिखाते हैं. ऐसे अनुरोध सिर्फ़ 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 ऑब्जेक्ट या यूआरएल (strings) की कैटगरी लेता है. यह हर अनुरोध के लिए cache.add को कॉल करने की तरह ही काम करता है. हालांकि, अगर कोई अनुरोध कैश मेमोरी में सेव नहीं है, तो Promise उसे अस्वीकार कर देता है.

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

इनमें से हर एक मामले में, एक नई एंट्री, मेल खाने वाली मौजूदा एंट्री की जगह ले लेती है. इसमें, प्रॉपर्टी वापस पाने वाले सेक्शन में बताए गए मैच करने के उन नियमों का इस्तेमाल किया जाता है.

cache.put

आखिर में, cache.put() है. इसकी मदद से, नेटवर्क से मिले रिस्पॉन्स को सेव किया जा सकता है या अपना Response बनाया और सेव किया जा सकता है. इसमें दो पैरामीटर होते हैं. पहला यूआरएल (string) या Request ऑब्जेक्ट हो सकता है. दूसरा, 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() की तुलना में ज़्यादा अनुमतियां होती हैं. साथ ही, यह आपको बिना सीओआरएस के रिस्पॉन्स या ऐसे अन्य रिस्पॉन्स को सेव करने की अनुमति देती है जिनमें रिस्पॉन्स का स्टेटस कोड 200 रेंज में न हो. ऐसा करने से, एक ही अनुरोध के लिए, पिछले रिस्पॉन्स को ओवरराइट कर दिया जाएगा.

अनुरोध ऑब्जेक्ट बनाना

सेव की जा रही चीज़ के यूआरएल का इस्तेमाल करके, Request ऑब्जेक्ट बनाएं:

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');

सही हेडर सेट करके, Response का MIME टाइप सेट किया जा सकता है.

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

अगर आपने Response को वापस पा लिया है और आपको इसका मुख्य हिस्सा ऐक्सेस करना है, तो इसे इस्तेमाल करने के कई तरीके हैं. हर नतीजा एक Promise दिखाता है, जिसकी वैल्यू अलग तरह की होती है.

तरीका ब्यौरा
arrayBuffer बाइट में सीरियलाइज़ किए गए मुख्य हिस्से वाले ArrayBuffer को दिखाता है.
blob Blob दिखाता है. अगर Response को Blob का इस्तेमाल करके बनाया गया था, तो इस नए Blob का टाइप एक जैसा है. ऐसा न करने पर, Response के Content-Type का इस्तेमाल किया जाता है.
text मुख्य हिस्से के बाइट को UTF-8 कोड में बदली गई स्ट्रिंग के तौर पर समझता है.
json बॉडी के बाइट को UTF-8 एन्कोड की गई स्ट्रिंग के तौर पर समझता है. इसके बाद, इसे JSON के तौर पर पार्स करने की कोशिश करता है. नतीजे के तौर पर मिलने वाला ऑब्जेक्ट लौटाता है या अगर स्ट्रिंग को JSON के रूप में पार्स नहीं किया जा सकता, तो TypeError दिखाता है.
formData बॉडी के बाइट को एचटीएमएल फ़ॉर्म के तौर पर समझता है. इसे 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 दिखाता है जो Response के बराबर होता है या नहीं होने पर undefined दिखाता है.

दो Requests मैच करते हैं या नहीं, यह तय करने के लिए ब्राउज़र सिर्फ़ यूआरएल का इस्तेमाल नहीं करता. अगर दो अनुरोधों में अलग-अलग क्वेरी स्ट्रिंग, Vary हेडर या एचटीटीपी के तरीके (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.`);

शॉर्टकट के तौर पर, सभी कैश मेमोरी को एक साथ खोजा जा सकता है. इसके लिए, हर कैश मेमोरी के लिए cache.match() को कॉल करने के बजाय, caches.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 को इस तरह के ऑपरेशन के लिए डिज़ाइन किया गया है. इसलिए, बड़ी संख्या में एंट्री के साथ इसकी परफ़ॉर्मेंस बेहतर होती है.

अगर खोजी जा सकने वाली प्रॉपर्टी के साथ-साथ Request का यूआरएल भी सेव किया जाता है, तो खोज करने के बाद सही कैश मेमोरी एंट्री को आसानी से वापस पाया जा सकता है.

कोई आइटम मिटाना

कैश मेमोरी से किसी आइटम को मिटाने के लिए:

cache.delete(request);

यहां अनुरोध, Request या यूआरएल स्ट्रिंग हो सकती है. इस तरीके में भी cache.match के तौर पर वही विकल्प ऑब्जेक्ट लिया जाता है. इससे, एक ही यूआरएल के लिए कई Request/Response पेयर मिटाए जा सकते हैं.

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

कैश मेमोरी मिटाना

कैश मेमोरी मिटाने के लिए, caches.delete(name) को कॉल करें. अगर कैश मेमोरी मौजूद है और मिटा दिया गया है, तो यह फ़ंक्शन Promise बताता है जो true में बदलता है. अगर कैश मेमोरी मौजूद नहीं है, तो यह फ़ंक्शन false बताता है.

धन्यवाद

इस लेख का मूल वर्शन लिखने वाले मैट स्केल को धन्यवाद. यह लेख पहली बार WebFundamentals पर पब्लिश हुआ था.