IndexedDB का इस्तेमाल करने के सबसे सही तरीके

IndexedDB एक लोकप्रिय स्टेट मैनेजमेंट लाइब्रेरी के बीच ऐप्लिकेशन की स्थिति को सिंक करने के सबसे सही तरीके जानें.

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

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

IndexedDB का एक और अच्छा इस्तेमाल, यूज़र जनरेटेड कॉन्टेंट को सेव करना है. यह कॉन्टेंट, सर्वर पर अपलोड किए जाने से पहले एक अस्थायी स्टोर के तौर पर या रिमोट डेटा के क्लाइंट-साइड कैश के तौर पर सेव किया जाता है. इसके अलावा, दोनों को भी स्टोर किया जा सकता है.

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

अपने ऐप्लिकेशन के लिए अनुमान लगाना आसान बनाएं

IndexedDB स्टेम से जुड़ी कई समस्याएं इस वजह से है कि ऐसे कई कारक हैं जिन पर आपका (डेवलपर) कोई कंट्रोल नहीं है. इस सेक्शन में ऐसी कई समस्याओं के बारे में जानकारी दी गई है जिनका इंडेक्स डीबी के साथ काम करते समय ध्यान रखना ज़रूरी है.

सभी प्लैटफ़ॉर्म पर IndexedDB में सब कुछ सेव नहीं किया जा सकता

अगर इमेज या वीडियो जैसी यूज़र जनरेटेड फ़ाइलें सेव की जा रही हैं, तो उन्हें File या Blob ऑब्जेक्ट के तौर पर सेव करें. यह कुछ प्लैटफ़ॉर्म पर काम करेगा, लेकिन अन्य प्लैटफ़ॉर्म पर काम नहीं करेगा. खास तौर पर, iOS पर Safari Blobs को IndexedDB में सेव नहीं कर सकता.

अच्छी बात यह है कि किसी Blob को ArrayBuffer में बदलना बहुत मुश्किल नहीं है और इसके उलट भी. IndexedDB में ArrayBuffer को स्टोर करने से, अच्छी तरह से मदद मिल सकती है.

हालांकि, याद रखें कि Blob में MIME टाइप होता है, जबकि ArrayBuffer में नहीं. सही तरीके से कन्वर्ज़न करने के लिए, आपको बफ़र के साथ टाइप को स्टोर करना होगा.

ArrayBuffer को Blob में बदलने के लिए, आपको सिर्फ़ Blob कंस्ट्रक्टर का इस्तेमाल करना होगा.

function arrayBufferToBlob(buffer, type) {
  return new Blob([buffer], { type: type });
}

दूसरी दिशा थोड़ी ज़्यादा शामिल है और यह एक एसिंक्रोनस प्रोसेस है. BLOB को ArrayBuffer के तौर पर पढ़ने के लिए, FileReader ऑब्जेक्ट का इस्तेमाल किया जा सकता है. रीडिंग पूरी होने पर, रीडर पर loadend इवेंट ट्रिगर होता है. इस प्रोसेस को Promise में इस तरह पूरा किया जा सकता है:

function blobToArrayBuffer(blob) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.addEventListener('loadend', () => {
      resolve(reader.result);
    });
    reader.addEventListener('error', reject);
    reader.readAsArrayBuffer(blob);
  });
}

डिवाइस के स्टोरेज में सेव नहीं किया जा सका

IndexedDB पर लिखते समय गड़बड़ियां होने की कई वजहें हो सकती हैं. कुछ मामलों में, डेवलपर के तौर पर ये वजहें आपके कंट्रोल से बाहर होती हैं. उदाहरण के लिए, फ़िलहाल कुछ ब्राउज़र निजी ब्राउज़िंग मोड में होने पर IndexedDB में लिखने की अनुमति नहीं देते. ऐसा भी हो सकता है कि उपयोगकर्ता किसी ऐसे डिवाइस का इस्तेमाल कर रहा हो जिसके डिस्क में स्टोरेज खत्म होने वाला है और ब्राउज़र आपको कुछ भी सेव करने से रोक देगा.

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

जब भी आप IDBDatabase, IDBTransaction या IDBRequest ऑब्जेक्ट बनाते हैं, तब error इवेंट के लिए कोई इवेंट हैंडलर जोड़कर, IndexedDB कार्रवाइयों में गड़बड़ी पकड़ सकते हैं.

const request = db.open('example-db', 1);
request.addEventListener('error', (event) => {
  console.log('Request error:', request.error);
};

ऐसा हो सकता है कि उपयोगकर्ता ने सेव किए गए डेटा में बदलाव किया हो या उसे मिटा दिया हो

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

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

सेव किया गया डेटा पुराना हो सकता है

पिछले सेक्शन की तरह ही, भले ही उपयोगकर्ता ने डेटा में बदलाव न किया हो, लेकिन ऐसा हो सकता है कि उसके स्टोरेज में मौजूद डेटा को आपके कोड के किसी पुराने वर्शन से लिखा गया हो. यह ऐसे वर्शन हो सकता है जिसमें गड़बड़ियां हों.

IndexedDB में स्कीमा वर्शन के लिए सहायता पहले से मौजूद है और यह इसके IDBOpenDBRequest.onupgradeneeded() तरीके से अपग्रेड करने की सुविधा देता है. हालांकि, आपको अब भी अपना अपग्रेड कोड इस तरह से लिखना होगा कि वह पिछले वर्शन से आने वाले उपयोगकर्ता को हैंडल कर सके (इसमें गड़बड़ी वाला वर्शन भी शामिल है).

यहां यूनिट टेस्ट काफ़ी मददगार हो सकते हैं, क्योंकि अक्सर सभी संभावित अपग्रेड पाथ और केस की मैन्युअल तौर पर जांच करना संभव नहीं होता.

अपने ऐप्लिकेशन की परफ़ॉर्मेंस बेहतर बनाए रखना

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

एक सामान्य नियम के तौर पर, IndexedDB में लिखे गए और पढ़ना, ऐक्सेस किए जा रहे डेटा के लिए ज़रूरी से ज़्यादा नहीं होने चाहिए.

हालांकि, IndexedDB की मदद से बड़े और नेस्ट किए गए ऑब्जेक्ट को एक ही रिकॉर्ड के तौर पर सेव किया जा सकता है (और डेवलपर के नज़रिए से ऐसा करना काफ़ी आसान है), लेकिन इस तरीके से बचना चाहिए. इसकी वजह यह है कि जब IndexedDB किसी ऑब्जेक्ट को सेव करता है, तो पहले उसे उस ऑब्जेक्ट का स्ट्रक्चर्ड क्लोन बनाना होता है. साथ ही, स्ट्रक्चर्ड क्लोनिंग की प्रोसेस मुख्य थ्रेड पर होती है. ऑब्जेक्ट जितना बड़ा होगा, उसे ब्लॉक करने में उतना ही ज़्यादा समय लगेगा.

इस तरह, IndexedDB पर ऐप्लिकेशन की स्थिति को बनाए रखने की योजना बनाते समय कुछ चुनौतियां आती हैं. इसकी वजह यह है कि ज़्यादातर लोकप्रिय स्टेट मैनेजमेंट लाइब्रेरी (जैसे कि Redux) आपके पूरे स्टेट ट्री को एक ही JavaScript ऑब्जेक्ट के तौर पर मैनेज करके काम करती हैं.

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

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

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

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

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

मीटिंग में सामने आए नतीजे

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

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

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