ऑफ़लाइन डेटा

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

स्टोरेज

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

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

सपोर्ट किए गए प्लैटफ़ॉर्म पर, Storage Manager API की मदद से, डिवाइस के स्टोरेज को मैनेज किया जा सकता है. Cache Storage API और IndexedDB, PWAs के लिए परसिस्टेंट स्टोरेज का एसिंक्रोनस ऐक्सेस देते हैं. इन्हें मुख्य थ्रेड, वेब वर्कर, और सर्विस वर्कर से ऐक्सेस किया जा सकता है. नेटवर्क की कनेक्टिविटी कमज़ोर होने या न होने पर, PWAs को भरोसेमंद तरीके से काम करने में ये दोनों अहम भूमिका निभाते हैं. हालांकि, आपको इनमें से हर एक का इस्तेमाल कब करना चाहिए?

नेटवर्क रिसॉर्स के लिए, Cache Storage API का इस्तेमाल करें. ये ऐसे आइटम होते हैं जिन्हें यूआरएल के ज़रिए ऐक्सेस किया जाता है. जैसे, एचटीएमएल, सीएसएस, JavaScript, इमेज, वीडियो, और ऑडियो.

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

IndexedDB

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

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

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

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

  1. openDB फ़ंक्शन का इस्तेमाल करके, cookbook नाम का नया IndexedDB डेटाबेस बनाएं. IndexedDB डेटाबेस के वर्शन होते हैं. इसलिए, डेटाबेस के स्ट्रक्चर में बदलाव करने पर, आपको वर्शन नंबर बढ़ाना होगा. दूसरा पैरामीटर, डेटाबेस का वर्शन है. उदाहरण में, इसे 1 पर सेट किया गया है.
  2. openDB() को एक इनिशियलाइज़ेशन ऑब्जेक्ट पास किया जाता है. इसमें upgrade() कॉलबैक होता है. डेटाबेस को पहली बार इंस्टॉल करने या नए वर्शन में अपग्रेड करने पर, कॉलबैक फ़ंक्शन को कॉल किया जाता है. यह फ़ंक्शन ही वह जगह है जहां कार्रवाइयां की जा सकती हैं. इन कार्रवाइयों में, नए ऑब्जेक्ट स्टोर बनाना (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;
}

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

डेटा वापस लाया जा रहा है

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, वेब स्टोरेज, और यहां तक कि सर्विस वर्कर फ़ाइल और उसकी डिपेंडेंसी भी शामिल हैं. हालांकि, अलग-अलग ब्राउज़र में अलग-अलग स्टोरेज उपलब्ध होता है. आपको शायद ही कभी स्टोरेज की समस्या आए. ऐसा इसलिए, क्योंकि कुछ ब्राउज़र पर साइटें, मेगाबाइट और यहां तक कि गीगाबाइट में डेटा सेव कर सकती हैं. उदाहरण के लिए, Chrome ब्राउज़र को कुल डिस्क स्पेस का 80% तक इस्तेमाल करने की अनुमति देता है. साथ ही, कोई ओरिजन कुल डिस्क स्पेस का 60% तक इस्तेमाल कर सकता है. 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 के लिए कोई आइकॉन इंस्टॉल किया है, तो ब्राउज़र लगातार स्टोरेज का ऐक्सेस दे सकता है.

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

एपीआई ब्राउज़र के साथ काम करता है

वेब स्टोरेज

Browser Support

  • Chrome: 4.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 4.

Source

फ़ाइल सिस्टम को ऐक्सेस करने की सुविधा

Browser Support

  • Chrome: 86.
  • Edge: 86.
  • Firefox: 111.
  • Safari: 15.2.

Source

जगह मैनेजर

Browser Support

  • Chrome: 55.
  • Edge: 79.
  • Firefox: 57.
  • Safari: 15.2.

Source

संसाधन