इंपेरेटिव कैशिंग गाइड

Andrew Guan
Andrew Guan

कुछ वेबसाइटों को नतीजों के बारे में सूचना दिए बिना, सर्विस वर्कर से संपर्क करना पड़ सकता है. यहां कुछ उदाहरण दिए गए हैं:

  • पेज, सर्विस वर्कर को प्रीफ़ेच के लिए यूआरएल की सूची भेजता है, ताकि जब उपयोगकर्ता किसी लिंक पर क्लिक करे, तब दस्तावेज़ या पेज के सबरिसॉर्स, कैश मेमोरी में पहले से उपलब्ध रहें. इससे बाद वाला नेविगेशन ज़्यादा तेज़ी से होता है.
  • यह पेज सर्विस वर्कर को प्रमुख लेखों के सेट को वापस पाने और कैश मेमोरी में सेव करने के लिए कहता है, ताकि उन्हें ऑफ़लाइन इस्तेमाल के लिए उपलब्ध कराया जा सके.

सर्विस वर्कर को इस तरह के गैर-ज़रूरी टास्क देने से मुख्य थ्रेड खाली हो जाती है. इससे, उपयोगकर्ता की बातचीत का जवाब देने जैसे ज़रूरी कामों को बेहतर तरीके से मैनेज किया जा सकता है.

सर्विस वर्कर को संसाधनों को कैश मेमोरी में सेव करने का अनुरोध करने वाले पेज का डायग्राम.

इस गाइड में, हम एक्सप्लोर करेंगे कि स्टैंडर्ड ब्राउज़र एपीआई और Workbox लाइब्रेरी का इस्तेमाल करके, पेज से सर्विस वर्कर तक एकतरफ़ा कम्यूनिकेशन तकनीक को कैसे लागू किया जाता है. हम इस तरह के इस्तेमाल के उदाहरणों को इंपेरेटिव कैश मेमोरी कहेंगे.

प्रोडक्शन केस

1-800-flowers.com ने प्रॉडक्ट के बारे में जानकारी वाले पेजों पर तेज़ी से जाने के लिए, कैटगरी पेजों में सबसे ऊपर मौजूद आइटम को प्रीफ़ेच करने के लिए, postMessage() के ज़रिए सर्विस वर्कर के साथ इंपेरेटिव कैशिंग (प्रीफ़ेचिंग) लागू की.

1 से 800 के फूलों का लोगो.

किन आइटम को प्रीफ़ेच करना है, यह तय करने के लिए वे मिली-जुली तकनीक का इस्तेमाल करते हैं:

  • पेज लोड होने पर, वह सर्विसर वर्कर को मुख्य नौ आइटम के लिए JSON डेटा वापस पाने और नतीजे में मिलने वाले रिस्पॉन्स ऑब्जेक्ट को कैश मेमोरी में जोड़ने के लिए कहती है.
  • बचे हुए आइटम के लिए, वे mouseover इवेंट को सुनते हैं. इससे, जब कोई उपयोगकर्ता कर्सर को किसी आइटम के ऊपर ले जाता है, तो "मांग" पर संसाधन के लिए फ़ेच ट्रिगर किया जा सकता है.

वे JSON रिस्पॉन्स को स्टोर करने के लिए, कैश एपीआई का इस्तेमाल करते हैं:

1 से 800 के फूलों का लोगो.
1-800flowers.com में प्रॉडक्ट लिस्टिंग पेजों से JSON प्रॉडक्ट डेटा को प्रीफ़ेच करना.

जब उपयोगकर्ता किसी आइटम पर क्लिक करता है, तो उससे जुड़े JSON डेटा को कैश मेमोरी से चुना जा सकता है. इसके लिए, नेटवर्क में जाने की ज़रूरत नहीं होती. इससे नेविगेशन तेज़ी से होता है.

Workbox का इस्तेमाल करना

Workbox, workbox-window पैकेज के ज़रिए किसी सर्विस वर्कर को मैसेज भेजने का आसान तरीका है, यह ऐसे मॉड्यूल का एक सेट है जो विंडो कॉन्टेक्स्ट में चलाने के लिए बनाया गया है. वे सर्विस वर्कर में चलने वाले अन्य Workbox पैकेज के साथ काम करते हैं.

पेज को सर्विस वर्कर से संपर्क करने के लिए, सबसे पहले रजिस्टर किए गए सर्विस वर्कर का Workspace ऑब्जेक्ट रेफ़रंस पाएं:

const wb = new Workbox('/sw.js');
wb.register();

इसके बाद, सीधे तौर पर जानकारी देकर मैसेज भेजा जा सकता है. आपको रजिस्ट्रेशन की, ऐक्टिवेशन की जांच करने या बुनियादी कम्यूनिकेशन एपीआई के बारे में सोचने की परेशानी नहीं होगी:

wb.messageSW({"type": "PREFETCH", "payload": {"urls": ["/data1.json", "data2.json"]}}); });

सर्विस वर्कर, इन मैसेज को सुनने के लिए message हैंडलर लागू करता है. यह विकल्प के तौर पर जवाब दे सकता है. हालांकि, ऐसे मामलों में, यह ज़रूरी नहीं है:

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PREFETCH') {
    // do something
  }
});

ब्राउज़र एपीआई का इस्तेमाल करना

अगर Workbox लाइब्रेरी आपकी ज़रूरतों के हिसाब से काफ़ी नहीं है, तो ब्राउज़र API का इस्तेमाल करके, सर्विस वर्कर कम्यूनिकेशन के लिए विंडो को लागू करने का तरीका यहां बताया गया है.

postMessage API का इस्तेमाल, पेज से सर्विस वर्कर तक एकतरफ़ा कम्यूनिकेशन करने के लिए किया जा सकता है.

पेज, सर्विस वर्कर इंटरफ़ेस पर postMessage() को कॉल करता है:

navigator.serviceWorker.controller.postMessage({
  type: 'MSG_ID',
  payload: 'some data to perform the task',
});

सर्विस वर्कर, इन मैसेज को सुनने के लिए message हैंडलर लागू करता है.

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === MSG_ID) {
    // do something
  }
});

{type : 'MSG_ID'} एट्रिब्यूट की वैल्यू देना ज़रूरी नहीं है. हालांकि, यह एक ऐसा तरीका है जिससे पेज को सर्विस वर्कर को अलग-अलग तरह के निर्देश भेजने की अनुमति मिलती है. इसका मतलब है कि ' प्रीफ़ेच करना' बनाम 'स्टोरेज खाली करना'. इस फ़्लैग के आधार पर, सर्विस वर्कर अलग-अलग एक्ज़ीक्यूशन पाथ में शामिल हो सकता है.

अगर कार्रवाई पूरी हो जाती है, तो उपयोगकर्ता को इससे फ़ायदे मिल जाएंगे. हालांकि, ऐसा न होने पर, मुख्य यूज़र फ़्लो में कोई बदलाव नहीं होगा. उदाहरण के लिए, जब 1-800-flowers.com प्रीकैश करने की कोशिश करता है, तो पेज को यह जानने की ज़रूरत नहीं होती कि सर्विस वर्कर सफल हुआ या नहीं. अगर ऐसा होता है, तो उपयोगकर्ता को तेज़ नेविगेशन का आनंद मिलेगा. अगर ऐसा नहीं होता, तो भी पेज को नए पेज पर जाने की ज़रूरत होती है. इसमें थोड़ा ज़्यादा समय लगेगा.

प्रीफ़ेच करने का सामान्य उदाहरण

इंपेरेटिव कैश मेमोरी के सबसे सामान्य ऐप्लिकेशन में से एक प्रीफ़ेचिंग है. इसका मतलब है कि नेविगेशन को तेज़ करने के लिए, उपयोगकर्ता के उस यूआरएल पर जाने से पहले उसके संसाधन फ़ेच करना.

साइटों में प्रीफ़ेच लागू करने के कई तरीके हैं:

प्रीफ़ेच करने के कुछ सामान्य मामलों, जैसे कि दस्तावेज़ों या खास एसेट (JS, सीएसएस वगैरह) को प्रीफ़ेच करने के लिए, ये तरीके सबसे सही होते हैं.

अगर किसी और लॉजिक की ज़रूरत हो, जैसे कि प्रीफ़ेच संसाधन (JSON फ़ाइल या पेज) को उसके अंदरूनी यूआरएल को फ़ेच करने के लिए पार्स करना, तो बेहतर होगा कि इस टास्क को पूरी तरह से सर्विस वर्कर को सौंप दिया जाए.

सर्विस वर्कर को इस तरह की कार्रवाइयां करने के ये फ़ायदे हैं:

  • फ़ेच करने और पोस्ट-फ़ेच प्रोसेस (यह सुविधा बाद में शुरू की जाएगी) को सेकंडरी थ्रेड में लोड होने से रोकना. ऐसा करने से, यह मुख्य थ्रेड को काम के लिए इस्तेमाल करता है. जैसे, उपयोगकर्ताओं के इंटरैक्शन का जवाब देने जैसे काम.
  • एक से ज़्यादा क्लाइंट (जैसे, टैब) को किसी एक फ़ंक्शन का फिर से इस्तेमाल करने देना और मुख्य थ्रेड को ब्लॉक किए बिना, सेवा को एक साथ कॉल करने की अनुमति देना.

प्रॉडक्ट की जानकारी वाले पेजों को प्रीफ़ेच करें

सर्विस वर्कर इंटरफ़ेस पर सबसे पहले postMessage() का इस्तेमाल करें और कैश मेमोरी के लिए यूआरएल का कलेक्शन पास करें:

navigator.serviceWorker.controller.postMessage({
  type: 'PREFETCH',
  payload: {
    urls: [
      'www.exmaple.com/apis/data_1.json',
      'www.exmaple.com/apis/data_2.json',
    ],
  },
});

सर्विस वर्कर में, किसी भी चालू टैब से भेजे गए मैसेज को रोकने और प्रोसेस करने के लिए message हैंडलर लागू करें:

addEventListener('message', (event) => {
  let data = event.data;
  if (data && data.type === 'PREFETCH') {
    let urls = data.payload.urls;
    for (let i in urls) {
      fetchAsync(urls[i]);
    }
  }
});

पिछले कोड में, हमने fetchAsync() नाम का एक छोटा हेल्पर फ़ंक्शन लॉन्च किया था, जो यूआरएल की फिर से जांच करने और हर एक के लिए फ़ेच करने का अनुरोध जारी करता है:

async function fetchAsync(url) {
  // await response of fetch call
  let prefetched = await fetch(url);
  // (optionally) cache resources in the service worker storage
}

रिस्पॉन्स मिलने के बाद, रिसॉर्स के कैश मेमोरी में सेव किए गए हेडर पर भरोसा किया जा सकता है. हालांकि, कई मामलों में प्रॉडक्ट की जानकारी वाले पेजों की तरह, रिसॉर्स को कैश मेमोरी में सेव नहीं किया जाता (इसका मतलब है कि उनमें no-cache का एक Cache-control हेडर है). ऐसे मामलों में, सर्विस वर्कर कैश में फ़ेच किए गए संसाधन को सेव करके, इस व्यवहार को बदला जा सकता है. इसका एक अतिरिक्त लाभ यह है कि फ़ाइल को ऑफ़लाइन स्थितियों में दिखाया जा सकता है.

JSON डेटा के अलावा अन्य सोर्स

JSON डेटा को सर्वर एंडपॉइंट से फ़ेच किए जाने के बाद, अक्सर इसमें ऐसे अन्य यूआरएल शामिल होते हैं जो प्रीफ़ेच किए जाने लायक होते हैं. जैसे, इस फ़र्स्ट-लेवल डेटा से जुड़ा इमेज या दूसरा एंडपॉइंट डेटा.

मान लें कि हमारे उदाहरण में, लौटाया गया JSON डेटा किराने के सामान की खरीदारी की साइट की जानकारी है:

{
  "productName": "banana",
  "productPic": "https://cdn.example.com/product_images/banana.jpeg",
  "unitPrice": "1.99"
 }

fetchAsync() कोड में बदलाव करके, उसे प्रॉडक्ट की सूची में फिर से डालें और हर प्रॉडक्ट के लिए हीरो इमेज को कैश मेमोरी में सेव करें:

async function fetchAsync(url, postProcess) {
  // await response of fetch call
  let prefetched = await fetch(url);

  //(optionally) cache resource in the service worker cache

  // carry out the post fetch process if supplied
  if (postProcess) {
    await postProcess(prefetched);
  }
}

async function postProcess(prefetched) {
  let productJson = await prefetched.json();
  if (productJson && productJson.product_pic) {
    fetchAsync(productJson.product_pic);
  }
}

404 जैसी स्थितियों के लिए इस कोड में कुछ अपवाद भी जोड़े जा सकते हैं. लेकिन प्रीफ़ेच करने के लिए किसी सर्विस वर्कर का इस्तेमाल करने की सबसे अच्छी बात यह है कि यह पेज और मुख्य थ्रेड के कुछ खास नतीजों के बिना काम नहीं कर सकता. प्रीफ़ेच किए गए कॉन्टेंट की पोस्ट-प्रोसेसिंग में, आपके पास ज़्यादा जानकारी वाला लॉजिक भी हो सकता है. इससे यह ज़्यादा सुविधाजनक हो जाता है और इसे मैनेज किए जा रहे डेटा के साथ अलग हो जाता है. नामुमकिन कुछ भी नहीं.

नतीजा

इस लेख में, हमने पेज और सर्विस वर्कर के बीच एकतरफ़ा कम्यूनिकेशन के सामान्य इस्तेमाल के उदाहरण के बारे में बताया है: इंपेरेटिव कैश मेमोरी. यहां दिए गए उदाहरण सिर्फ़ इस पैटर्न को इस्तेमाल करने का एक तरीका बताने के लिए हैं. इसी तरीके को दूसरे इस्तेमाल के उदाहरणों पर भी लागू किया जा सकता है. उदाहरण के लिए, ऑफ़लाइन इस्तेमाल की मांग पर लोकप्रिय लेखों को कैश मेमोरी में सेव करना, बुकमार्क करना वगैरह.

पेज और सर्विस वर्कर कम्यूनिकेशन के ज़्यादा पैटर्न के लिए, यहां जाएं:

  • ब्रॉडकास्ट अपडेट: ज़रूरी अपडेट के बारे में जानकारी देने के लिए, सर्विस वर्कर से पेज को कॉल करना (जैसे, वेबऐप का नया वर्शन उपलब्ध है).
  • दो-तरफ़ा बातचीत: किसी सर्विस वर्कर को कोई काम सौंपना (उदाहरण के लिए, बहुत ज़्यादा डाउनलोड करना) और पेज को उसकी प्रोग्रेस के बारे में जानकारी देना.