ऑफ़लाइन डेटा

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

स्टोरेज का इस्तेमाल सिर्फ़ फ़ाइलों और ऐसेट के लिए नहीं किया जा सकता, बल्कि इसमें अन्य तरह का डेटा भी शामिल हो सकता है. पीडब्ल्यूए के साथ काम करने वाले सभी ब्राउज़र पर, डिवाइस की मेमोरी के लिए ये एपीआई उपलब्ध हैं:

  • IndexedDB: स्ट्रक्चर्ड डेटा और BLOB (बाइनरी डेटा) के लिए, NoSQL ऑब्जेक्ट स्टोरेज का विकल्प.
  • WebStorage: लोकल स्टोरेज या सेशन स्टोरेज का इस्तेमाल करके, कुंजी/वैल्यू स्ट्रिंग पेयर को सेव करने का तरीका. यह सर्विस वर्कर के हिसाब से उपलब्ध नहीं है. यह एपीआई सिंक्रोनस है. इसलिए, कॉम्प्लेक्स डेटा स्टोरेज के लिए इसका सुझाव नहीं दिया जाता.
  • कैश मेमोरी: जैसा कि कैशिंग मॉड्यूल में बताया गया है.

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

एचटीएमएल, सीएसएस, JavaScript, इमेज, वीडियो, और ऑडियो जैसे यूआरएल के ज़रिए अनुरोध करके, नेटवर्क संसाधनों को ऐक्सेस करने के लिए कैश मेमोरी एपीआई का इस्तेमाल करें.

स्ट्रक्चर्ड डेटा स्टोर करने के लिए, IndexedDB का इस्तेमाल करें. इसमें ऐसा डेटा शामिल होता है जिसे NoSQL जैसे तरीके से खोजा जा सके या जोड़ा जा सके. इसके अलावा, इसमें उपयोगकर्ता से जुड़ा कोई ऐसा डेटा भी शामिल है जिसका यूआरएल अनुरोध से मेल खाना ज़रूरी नहीं है. ध्यान दें कि IndexedDB को पूरे टेक्स्ट की खोज के लिए डिज़ाइन नहीं किया गया है.

IndexedDB

IndexedDB का इस्तेमाल करने के लिए, पहले एक डेटाबेस खोलें. कोई डेटाबेस मौजूद न होने पर, यह एक नया डेटाबेस बना देता है. IndexedDB एक एसिंक्रोनस एपीआई है, लेकिन यह प्रॉमिस दिखाने के बजाय कॉलबैक की मदद लेता है. नीचे दिए गए उदाहरण में, जेक आर्चिबाल्ड की idb लाइब्रेरी का इस्तेमाल किया गया है, जो IndexedDB के लिए एक छोटा, प्रॉमिस रैपर है. IndexedDB का इस्तेमाल करने के लिए, हेल्पर लाइब्रेरी की ज़रूरत नहीं होती है. हालांकि, अगर आपको प्रॉमिस सिंटैक्स का इस्तेमाल करना है, तो idb लाइब्रेरी का इस्तेमाल किया जा सकता है.

नीचे दिए गए उदाहरण में, खाना बनाने की रेसिपी को सेव करने के लिए डेटाबेस बनाया गया है.

डेटाबेस बनाना और खोलना

डेटाबेस खोलने के लिए:

  1. cookbook नाम का एक नया IndexedDB डेटाबेस बनाने के लिए openDB फ़ंक्शन का इस्तेमाल करें. IndexedDB डेटाबेस के वर्शन वाला होने की वजह से, आपको डेटाबेस के स्ट्रक्चर में बदलाव करने पर वर्शन नंबर बढ़ाना होगा. दूसरा पैरामीटर, डेटाबेस वर्शन है. उदाहरण में, इसे 1 पर सेट किया गया है.
  2. upgrade() कॉलबैक वाला शुरुआती ऑब्जेक्ट, openDB() को पास किया जाता है. कॉलबैक फ़ंक्शन तब कॉल किया जाता है, जब डेटाबेस पहली बार इंस्टॉल किया जाता है या जब वह किसी नए वर्शन पर अपग्रेड होता है. सिर्फ़ इस फ़ंक्शन की मदद से, कार्रवाइयां की जा सकती हैं. कार्रवाइयों में नए ऑब्जेक्ट स्टोर बनाना शामिल हो सकता है (संरचना IndexedDB, डेटा को व्यवस्थित करने के लिए इस्तेमाल करता है) या ऐसे इंडेक्स (जिन पर आप खोज करना चाहते हैं). इसी वजह से, डेटा दूसरी जगह भी भेजा जा सकता है. आम तौर पर, डेटाबेस के पुराने वर्शन के आधार पर, upgrade() फ़ंक्शन में break स्टेटमेंट वाला switch स्टेटमेंट नहीं होता है. यह हर चरण को क्रम से लगाता है.
import { openDB } from 'idb';

async function createDB() {
  // Using https://github.com/jakearchibald/idb
  const db = await openDB('cookbook', 1, {
    upgrade(db, oldVersion, newVersion, transaction) {
      // Switch over the oldVersion, *without breaks*, to allow the database to be incrementally upgraded.
    switch(oldVersion) {
     case 0:
       // Placeholder to execute when database is created (oldVersion is 0)
     case 1:
       // Create a store of objects
       const store = db.createObjectStore('recipes', {
         // The `id` property of the object will be the key, and be incremented automatically
           autoIncrement: true,
           keyPath: 'id'
       });
       // Create an index called `name` based on the `type` property of objects in the store
       store.createIndex('type', 'type');
     }
   }
  });
}

यह उदाहरण cookbook डेटाबेस में recipes नाम का एक ऑब्जेक्ट स्टोर बनाता है. इसमें id प्रॉपर्टी को स्टोर की इंडेक्स कुंजी के तौर पर सेट किया जाता है और type प्रॉपर्टी के आधार पर, type नाम का दूसरा इंडेक्स बनाया जाता है.

चलिए, अभी बनाए गए ऑब्जेक्ट स्टोर पर नज़र डालते हैं. ऑब्जेक्ट स्टोर में रेसिपी जोड़ने और Chromium पर आधारित ब्राउज़र पर DevTools या Safari पर Web Inspector खोलने के बाद, आपको ये चीज़ें देखने को मिलेंगी:

Safari और Chrome में IndexedDB कॉन्टेंट दिखा रहा है.

डेटा जोड़ा जा रहा है

IndexedDB, लेन-देन का इस्तेमाल करता है. लेन-देन में ग्रुप की कार्रवाइयां एक साथ होती हैं, ताकि वे एक इकाई के तौर पर घटित हो सकें. इनकी मदद से, यह पक्का किया जाता है कि डेटाबेस हमेशा एक जैसा हो. अगर आपके ऐप्लिकेशन की एक से ज़्यादा कॉपी चल रही हैं, तो भी ये बहुत ज़रूरी होते हैं. ऐसा इसलिए, ताकि एक ही डेटा को बार-बार न लिखा जा सके. डेटा जोड़ने के लिए:

  1. mode को readwrite पर सेट करके लेन-देन शुरू करें.
  2. ऑब्जेक्ट स्टोर पाएं, जहां आपको डेटा जोड़ना है.
  3. सेव किए जा रहे डेटा का इस्तेमाल करके add() को कॉल करें. तरीके को डिक्शनरी के तौर पर (की/वैल्यू पेयर के तौर पर) मिलता है और उसे ऑब्जेक्ट स्टोर में जोड़ दिया जाता है. शब्दकोश को स्ट्रक्चर्ड क्लोनिंग का इस्तेमाल करके क्लोन करने लायक होना चाहिए. अगर आपको कोई मौजूदा ऑब्जेक्ट अपडेट करना है, तो इसके बजाय put() तरीके को कॉल करें.

लेन-देन में एक done प्रॉमिस होता है, जिसका समाधान लेन-देन पूरा होने पर होता है या लेन-देन में गड़बड़ी होने पर अस्वीकार हो जाता है.

जैसा कि IDB लाइब्रेरी के दस्तावेज़ में बताया गया है, अगर डेटाबेस में लिखा जा रहा है, तो tx.done से पता चलता है कि डेटाबेस के हिसाब से सब कुछ सही तरीके से पूरा हुआ. हालांकि, हर कार्रवाई के लिए इंतज़ार करना बेहतर होता है, ताकि आपको ऐसी कोई भी गड़बड़ी दिखे जिसकी वजह से लेन-देन पूरा नहीं हो सका.

// Using https://github.com/jakearchibald/idb
async function addData() {
  const cookies = {
      name: "Chocolate chips cookies",
      type: "dessert",
        cook_time_minutes: 25
  };
  const tx = await db.transaction('recipes', 'readwrite');
  const store = tx.objectStore('recipes');
  store.add(cookies);
  await tx.done;
}

कुकी जोड़ने के बाद, डेटाबेस में दूसरी रेसिपी के साथ रेसिपी भी जुड़ जाएगी. आईडी अपने-आप सेट हो जाता है और indexDB के हिसाब से इसकी वैल्यू बढ़ जाती है. अगर इस कोड को दो बार चलाया जाता है, तो आपके पास एक जैसी कुकी एंट्री होंगी.

डेटा फ़ेच किया जा रहा है

IndexedDB से डेटा पाने का तरीका यहां बताया गया है:

  1. ट्रांज़ैक्शन शुरू करें और ऑब्जेक्ट स्टोर या स्टोर के बारे में बताएं. साथ ही, यह भी बताएं कि लेन-देन का टाइप क्या है.
  2. इस लेन-देन से जुड़े objectStore() को कॉल करें. पक्का करें कि आपने ऑब्जेक्ट स्टोर का नाम डाला हो.
  3. आपको जो कुंजी चाहिए उसे get() पर कॉल करें. डिफ़ॉल्ट रूप से, स्टोर अपनी कुंजी का इस्तेमाल इंडेक्स के तौर पर करता है.
// Using https://github.com/jakearchibald/idb
async function getData() {
  const tx = await db.transaction('recipes', 'readonly')
  const store = tx.objectStore('recipes');
// Because in our case the `id` is the key, we would
// have to know in advance the value of the id to
// retrieve the record
  const value = await store.get([id]);
}

स्टोरेज मैनेजर

अपने PWA के स्टोरेज को मैनेज करने का तरीका जानना बेहद ज़रूरी है, ताकि नेटवर्क पर मिलने वाले जवाबों को सही तरीके से सेव और स्ट्रीम किया जा सके.

स्टोरेज कपैसिटी को स्टोरेज के सभी विकल्पों के साथ शेयर किया जाता है. इनमें कैश मेमोरी, IndexedDB, Web Storage, और यहां तक कि सर्विस वर्कर फ़ाइल और उसकी डिपेंडेंसी भी शामिल है. हालांकि, हर ब्राउज़र के लिए उपलब्ध स्टोरेज की मात्रा अलग-अलग होती है. शायद आपके खाते का स्टोरेज खत्म न हो; साइटें कुछ ब्राउज़र पर मेगाबाइट और यहां तक कि गीगाबाइट्स डेटा भी स्टोर कर सकती हैं. उदाहरण के लिए, Chrome, ब्राउज़र को डिस्क में बचे कुल स्टोरेज का 80% तक इस्तेमाल करने की अनुमति देता है. साथ ही, कोई ऑरिजिन, डिस्क के पूरे स्टोरेज के 60% तक का इस्तेमाल कर सकता है. Storage API के साथ काम करने वाले ब्राउज़र से यह पता किया जा सकता है कि आपके ऐप्लिकेशन के लिए अब भी कितना स्टोरेज उपलब्ध है, उसका कोटा कितना है, और उसे इस्तेमाल करने का कितना स्टोरेज है. नीचे दिए गए उदाहरण में, अनुमानित कोटा और इस्तेमाल की जानकारी पाने के लिए Storage API का इस्तेमाल किया गया है. इसके बाद, इस्तेमाल किए गए प्रतिशत और बचे हुए बाइट का हिसाब लगाया जाता है. ध्यान दें कि navigator.storage, StorageManager का इंस्टेंस दिखाता है. Storage का एक अलग इंटरफ़ेस मौजूद है. इसलिए, इससे उपयोगकर्ताओं को गुमराह करना आसान होता है.

if (navigator.storage && navigator.storage.estimate) {
  const quota = await navigator.storage.estimate();
  // quota.usage -> Number of bytes used.
  // quota.quota -> Maximum number of bytes available.
  const percentageUsed = (quota.usage / quota.quota) * 100;
  console.log(`You've used ${percentageUsed}% of the available storage.`);
  const remaining = quota.quota - quota.usage;
  console.log(`You can write up to ${remaining} more bytes.`);
}

Chromium DevTools में, आप ऐप्लिकेशन टैब में स्टोरेज सेक्शन खोलकर, साइट के कोटा और इस्तेमाल की जा रही मेमोरी के हिसाब से देख सकते हैं कि कितना स्टोरेज इस्तेमाल किया जा रहा है.

ऐप्लिकेशन में Chrome DevTools, मेमोरी मिटाएं सेक्शन

Firefox और Safari, सभी मेमोरी कोटा और मौजूदा ऑरिजिन के लिए इस्तेमाल किए गए डेटा को देखने के लिए खास जानकारी वाली स्क्रीन नहीं देते हैं.

डेटा परसिस्टेंस

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

स्थायी स्टोरेज का अनुरोध करने के लिए, StorageManager.persist() पर कॉल करें. पहले की तरह ही, StorageManager इंटरफ़ेस को navigator.storage प्रॉपर्टी के ज़रिए ऐक्सेस किया जा सकता है.

async function persistData() {
  if (navigator.storage && navigator.storage.persist) {
    const result = await navigator.storage.persist();
    console.log(`Data persisted: ${result}`);
}

यह भी देखा जा सकता है कि मौजूदा ऑरिजिन में, StorageManager.persisted() पर कॉल करके पहले से ही स्थायी स्टोरेज दिया गया है या नहीं. Firefox उपयोगकर्ता से स्थायी जगह का उपयोग करने की अनुमति का अनुरोध करता है. Chromium पर आधारित ब्राउज़र, उपयोगकर्ता के लिए कॉन्टेंट की अहमियत का पता लगाने के लिए ह्यूरिस्टिक के आधार पर परसिस्टेंस देते हैं या अस्वीकार करते हैं. उदाहरण के लिए, Google Chrome के लिए PWA इंस्टॉल करना एक ज़रूरी शर्त है. अगर उपयोगकर्ता ने ऑपरेटिंग सिस्टम में PWA के लिए आइकॉन इंस्टॉल किया है, तो ब्राउज़र उसे स्थायी स्टोरेज दे सकता है.

Mozilla Firefox, उपयोगकर्ता से स्टोरेज परसिस्टेंस की अनुमति मांग रहा है.

एपीआई ब्राउज़र के लिए सहायता

वेब स्टोरेज

ब्राउज़र सहायता

  • Chrome: 4. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • एज: 12. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • Firefox: 3.5. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • सफ़ारी: 4. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है

सोर्स

फ़ाइल सिस्टम का ऐक्सेस

ब्राउज़र सहायता

  • Chrome: 86. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • एज: 86. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • Firefox: 111. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • Safari: 15.2. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है

सोर्स

जगह मैनेजर

ब्राउज़र सहायता

  • Chrome: 55. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • एज: 79. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • Firefox: 57. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है
  • Safari: 15.2. अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है

सोर्स

संसाधन