ऑफ़लाइन डेटा

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

डिवाइस का स्टोरेज

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

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

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

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

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

IndexedDB

IndexedDB का इस्तेमाल करने के लिए, पहले कोई डेटाबेस खोलें. मौजूद न होने पर, एक नया डेटाबेस बन जाता है. IndexedDB एक एसिंक्रोनस एपीआई है. हालांकि, यह प्रॉमिस दिखाने के बजाय कॉलबैक लेता है. नीचे दिए गए उदाहरण में, जेक आर्चिबाल्ड की idb लाइब्रेरी का इस्तेमाल किया गया है, जो IndexedDB के लिए छोटा-सा प्रॉमिस रैपर है. IndexedDB का इस्तेमाल करने के लिए, हेल्पर लाइब्रेरी की ज़रूरत नहीं होती. हालांकि, अगर आपको Promise सिंटैक्स का इस्तेमाल करना है, तो 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');
     }
   }
  });
}

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

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

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

डेटा जोड़ना

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

  1. readwrite पर सेट किए गए mode से कोई लेन-देन शुरू करें.
  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 के साथ काम करने वाले ब्राउज़र के लिए, यह देखा जा सकता है कि आपके ऐप्लिकेशन के लिए अब भी कितना स्टोरेज उपलब्ध है. साथ ही, यह भी पता लगाया जा सकता है कि ऐप्लिकेशन के लिए कितना स्टोरेज उपलब्ध है. साथ ही, ऐप्लिकेशन के इस्तेमाल के बारे में भी जानकारी मिल सकती है. इस उदाहरण में, स्टोरेज एपीआई का इस्तेमाल करके, अनुमानित कोटा और इस्तेमाल के बारे में जानकारी दी गई है. इसके बाद, इस्तेमाल किए गए और बाकी बाइट के प्रतिशत का हिसाब लगाया जाता है. ध्यान दें कि 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, उपयोगकर्ता से डिवाइस के स्टोरेज को बनाए रखने की अनुमति मांग रहा है.

एपीआई ब्राउज़र से जुड़ी सहायता

वेब स्टोरेज

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

  • 4
  • 12
  • 3.5
  • 4

सोर्स

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

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

  • 86
  • 86
  • 111
  • 78 जीबी में से

सोर्स

जगह मैनेजर

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

  • 55
  • 79
  • 57
  • 78 जीबी में से

सोर्स

रिसॉर्स