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

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

फ़िलिप वॉल्टन
फ़िलिप वॉल्टन

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

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

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

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

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

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

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

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

सौभाग्य से, एक Blob को ArrayBuffer और इसके विपरीत बदलना बहुत मुश्किल नहीं है. IndexedDB में ArrayBuffers को स्टोर करना काफ़ी सही है.

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

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

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

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

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

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