ऑफ़लाइन अनुभव बेहतर बनाने के लिए, आपके PWA को स्टोरेज मैनेजमेंट की ज़रूरत होती है. कैश मेमोरी सेव करने के बारे में बताने वाले चैप्टर में, आपको पता चला था कि डिवाइस पर डेटा सेव करने के लिए, कैश मेमोरी स्टोरेज का विकल्प इस्तेमाल किया जा सकता है. इस चैप्टर में, हम आपको ऑफ़लाइन डेटा को मैनेज करने का तरीका बताएंगे. इसमें डेटा के सेव रहने की अवधि, सीमाएं, और उपलब्ध टूल शामिल हैं.
स्टोरेज
स्टोरेज में सिर्फ़ फ़ाइलें और एसेट ही नहीं, बल्कि दूसरी तरह का डेटा भी शामिल हो सकता है. PWA के साथ काम करने वाले सभी ब्राउज़र पर, डिवाइस के स्टोरेज के लिए ये एपीआई उपलब्ध हैं:
- IndexedDB: स्ट्रक्चर्ड डेटा और ब्लॉब (बाइनरी डेटा) के लिए, NoSQL ऑब्जेक्ट स्टोरेज का विकल्प.
- WebStorage: यह लोकल स्टोरेज या सेशन स्टोरेज का इस्तेमाल करके, की/वैल्यू स्ट्रिंग पेयर को सेव करने का एक तरीका है. यह सेवा वर्कर के संदर्भ में उपलब्ध नहीं है. यह एपीआई सिंक्रोनस है. इसलिए, इसका सुझाव जटिल डेटा स्टोरेज के लिए नहीं दिया जाता.
- कैश मेमोरी: कैश मेमोरी मॉड्यूल में बताया गया है.
काम करने वाले प्लैटफ़ॉर्म पर, Storage Manager API की मदद से, डिवाइस का सारा स्टोरेज मैनेज किया जा सकता है. Cache Storage API और IndexedDB, PWA के लिए पर्सिस्टेंट स्टोरेज का असाइनोक्रोनस ऐक्सेस देते हैं. साथ ही, इन्हें मुख्य थ्रेड, वेब वर्कर्स, और सेवा वर्कर्स से ऐक्सेस किया जा सकता है. नेटवर्क के काम न करने या मौजूद न होने पर, PWA को भरोसेमंद तरीके से काम करने में, ये दोनों अहम भूमिकाएं निभाते हैं. लेकिन इनमें से हर एक का इस्तेमाल कब करना चाहिए?
Cache Storage API का इस्तेमाल, नेटवर्क रिसॉर्स के लिए करें. इन रिसॉर्स को यूआरएल के ज़रिए ऐक्सेस किया जाता है. जैसे, एचटीएमएल, सीएसएस, JavaScript, इमेज, वीडियो, और ऑडियो.
स्ट्रक्चर्ड डेटा को स्टोर करने के लिए, IndexedDB का इस्तेमाल करें. इसमें ऐसा डेटा शामिल होता है जिसे NoSQL जैसे तरीके से खोजा जा सकता है या जोड़कर एक साथ इस्तेमाल किया जा सकता है. इसके अलावा, इसमें उपयोगकर्ता से जुड़ा ऐसा डेटा भी शामिल होता है जो ज़रूरी नहीं है कि वह यूआरएल के अनुरोध से मेल खाए. ध्यान दें कि IndexedDB को पूरे टेक्स्ट को खोजने के लिए डिज़ाइन नहीं किया गया है.
IndexedDB
IndexedDB का इस्तेमाल करने के लिए, पहले कोई डेटाबेस खोलें. अगर कोई डेटाबेस मौजूद नहीं है, तो यह एक नया डेटाबेस बनाता है.
IndexedDB एक असाइनोक्रोनस एपीआई है, लेकिन यह Promise दिखाने के बजाय कॉलबैक दिखाता है. नीचे दिए गए उदाहरण में, जैक आर्किबाल्ड की idb लाइब्रेरी का इस्तेमाल किया गया है. यह IndexedDB के लिए, Promise का एक छोटा रैपर है. IndexedDB का इस्तेमाल करने के लिए, हेल्पर लाइब्रेरी ज़रूरी नहीं हैं. हालांकि, अगर आपको Promise सिंटैक्स का इस्तेमाल करना है, तो idb
लाइब्रेरी का इस्तेमाल किया जा सकता है.
यहां दिए गए उदाहरण में, खाना बनाने की रेसिपी सेव करने के लिए डेटाबेस बनाया गया है.
डेटाबेस बनाना और खोलना
डेटाबेस खोलने के लिए:
cookbook
नाम का नया IndexedDB डेटाबेस बनाने के लिए,openDB
फ़ंक्शन का इस्तेमाल करें. IndexedDB डेटाबेस के वर्शन होते हैं. इसलिए, जब भी डेटाबेस के स्ट्रक्चर में बदलाव किया जाता है, तो आपको वर्शन नंबर बढ़ाना होगा. दूसरा पैरामीटर, डेटाबेस का वर्शन है. उदाहरण में, यह 1 पर सेट है.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 पर आधारित ब्राउज़र पर DevTools या Safari पर वेब इंस्पेक्टर खोलने के बाद, आपको यह दिखेगा:
डेटा जोड़ना
IndexedDB, लेन-देन का इस्तेमाल करता है. लेन-देन, कार्रवाइयों को एक साथ ग्रुप करते हैं, ताकि वे एक यूनिट के तौर पर हो सकें. इनसे यह पक्का करने में मदद मिलती है कि डेटाबेस हमेशा एक जैसा रहे. अगर आपके ऐप्लिकेशन की कई कॉपी चल रही हैं, तो एक ही डेटा में एक साथ बदलाव होने से रोकने के लिए, ये ज़रूरी हैं. डेटा जोड़ने के लिए:
mode
कोreadwrite
पर सेट करके लेन-देन शुरू करें.- वह ऑब्जेक्ट स्टोर पाएं जहां आपको डेटा जोड़ना है.
- सेव किए जा रहे डेटा के साथ
add()
को कॉल करें. इस तरीके से, डेटा को डिक्शनरी फ़ॉर्म (की/वैल्यू पेयर के तौर पर) में लिया जाता है और उसे ऑब्जेक्ट स्टोर में जोड़ा जाता है. स्ट्रक्चर्ड क्लोनिंग का इस्तेमाल करके, डिक्शनरी को क्लोन किया जा सकता हो. अगर आपको किसी मौजूदा ऑब्जेक्ट को अपडेट करना है, तो आपकोput()
तरीके को कॉल करना होगा.
लेन-देन के लिए done
एक वादा किया जाता है. यह वादा तब पूरा होता है, जब लेन-देन पूरा हो जाता है या लेन-देन में हुई गड़बड़ी की वजह से अस्वीकार कर दिया जाता है.
आईडीबी लाइब्रेरी के दस्तावेज़ में बताया गया है कि डेटाबेस में लिखने पर, 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 से डेटा पाने का तरीका यहां बताया गया है:
- लेन-देन शुरू करें और ऑब्जेक्ट स्टोर या स्टोर की जानकारी दें. इसके अलावा, लेन-देन का टाइप भी दिया जा सकता है.
- उस लेन-देन से
objectStore()
को कॉल करें. पक्का करें कि आपने ऑब्जेक्ट स्टोर का नाम डाला हो. - आपको जो पासकोड चाहिए उसके साथ
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 के साथ काम करने वाले ब्राउज़र के लिए, यह पता लगाया जा सकता है कि आपके ऐप्लिकेशन के लिए अब कितना स्टोरेज उपलब्ध है, उसका कोटा क्या है, और उसका इस्तेमाल कैसे किया जा रहा है.
इस उदाहरण में, कोटा और इस्तेमाल का अनुमान लगाने के लिए 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 में, ऐप्लिकेशन टैब में स्टोरेज सेक्शन खोलकर, अपनी साइट का कोटा और स्टोरेज के इस्तेमाल की जानकारी देखी जा सकती है. इसमें, यह भी देखा जा सकता है कि स्टोरेज का इस्तेमाल किस चीज़ के लिए किया जा रहा है.
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 के लिए कोई आइकॉन इंस्टॉल किया है, तो ब्राउज़र, स्टोरेज को हमेशा के लिए सेव करने की अनुमति दे सकता है.
एपीआई ब्राउज़र के लिए सहायता
वेब स्टोरेज
फ़ाइल सिस्टम का ऐक्सेस
जगह मैनेजर