वेब विकास में बहुत बार (और सामान्य रूप से प्रोग्रामिंग में) स्ट्रिंग्स के रूप में तार्किक मूल्यों (हाँ / नहीं, सही / गलत, जाँच / अनियंत्रित और इस तरह) की एक लंबी सूची को बचाने के लिए आवश्यक है। उदाहरण के लिए, आप कुकी में, स्थानीय डेटा का उपयोग करके ऐसा डेटा लिखना चाहते हैं या इसे HTTP अनुरोध के शरीर में भेज सकते हैं। मुझे सैकड़ों बार ऐसी जरूरत थी।
सरणी का उपयोग करना
हमारे पास एक सरणी में तार्किक डेटा को व्यवस्थित करने के दो उचित तरीके हैं।
पहला सच / गलत मूल्यों को संग्रहीत करना है:
[false, true, true, false, false, true, true]
दूसरा शून्य और लोगों की एक सरणी को संग्रहीत करना है:
[0, 1, 1, 0, 0, 1, 1]
जो भी विधि हम चुनते हैं, किसी भी स्थिति में, हमें इस तरह के एक सरणी को स्ट्रिंग में बदलना होगा, और फिर इस स्ट्रिंग को डेटा पढ़ने के बाद एक सरणी में परिवर्तित करना होगा। ऐसा करने के लिए, हम पुराने तरीकों
Array#join()
(या
Array#toString()
) और
String#split()
, या अधिक सुरुचिपूर्ण
JSON.stringify()
और
JSON.parse()
।
यदि हम JSON पथ का अनुसरण करते हैं, तो कोड थोड़ा छोटा होगा, हालांकि इस मामले में JSON का उपयोग करना एक चेनसॉ के साथ रोटी काटने की तरह है। कुछ ब्राउज़रों में,
प्रदर्शन पर इस दृष्टिकोण का
प्रभाव ध्यान देने योग्य होगा, यह पुराने ब्राउज़रों के लिए थोड़ा खराब समर्थन भी होगा।
सरणी-आधारित स्ट्रिंग्स का उपयोग करने का मुख्य नुकसान बाइट्स में उनका आकार है। यदि आप शून्य और लोगों के एक सरणी को संग्रहीत करने का विकल्प चुनते हैं, तो आपको प्रति मूल्य 2 वर्णों का उपयोग करना होगा (या, सटीक होने के लिए, 2n-1, प्रत्येक मान के बाद एक विभाजक, अंतिम को छोड़कर):
[0, 1, 1, 0, 0, 1, 1].toString().length
इस प्रकार, 512 मूल्यों के लिए, 1023 वर्ण या 2K की आवश्यकता होती है, क्योंकि
जावास्क्रिप्ट UTF-16 का उपयोग करता है ।
यदि हम सही / गलत मूल्यों की एक सरणी रखते हैं, तो चीजें और भी बदतर हो जाती हैं:
[false, true, true, false, false, true, true].toString().length
यह 5 या 6 अक्षर प्रति मूल्य है, 2560 से 3072 वर्ण प्रति 512 मान (5 से 6 केबी से)।
JSON.stringify()
कोष्ठक खोलने और बंद करने के लिए प्रत्येक मामले में 2 अधिक वर्णों का उपभोग करता है, लेकिन इसका लाभ यह है कि
JSON.parse()
परिणामस्वरूप हमें स्ट्रिंग्स के बजाय मूल मान प्रकार मिलते हैं।
स्ट्रिंग का उपयोग
स्ट्रिंग आपको वर्णों को सहेजने की अनुमति देता है, क्योंकि सीमांकक का उपयोग करने की कोई आवश्यकता नहीं है। उदाहरण के लिए, यदि हमने डिजिटल दृष्टिकोण को चुना और स्ट्रिंग को '01001101010111' स्टोर किया, तो हम प्रति मूल्य एक वर्ण का उपयोग करते हैं, जो एरे का उपयोग करते हुए दृष्टिकोण से बहुत बेहतर है।
String#split
का उपयोग करके आप हमारे मूल्यों को एक सरणी में रख सकते हैं:
'01001101010111'.split('');
इसके अलावा, आप स्ट्रिंग पर वर्णों पर
string.charAt(i)
कर सकते हैं। string में एक स्ट्रिंग का उपयोग करके
string.charAt(i)
या यहां तक कि स्ट्रिंग इंडेक्स
(string[i])
, अगर आपको पुराने ब्राउज़रों का समर्थन करने के बारे में चिंता करने की आवश्यकता नहीं है।
बिट फ़ील्ड का उपयोग करना
क्या आपने पिछले उदाहरण पर विचार करते हुए बाइनरी के बारे में भी सोचा है?
बिट फ़ील्ड की अवधारणा अन्य प्रोग्रामिंग भाषाओं में काफी लोकप्रिय है, लेकिन जावास्क्रिप्ट में नहीं। संक्षेप में, बिट फ़ील्ड का उपयोग किसी संख्या के तार्किक प्रतिनिधित्व के
बिट्स में कई तार्किक मूल्यों को पैक करने के लिए किया जाता है। उदाहरण के लिए, हमारे पास 8 मान हैं (सत्य, असत्य, असत्य, सत्य, असत्य, सत्य, सत्य, असत्य)। बाइनरी में, यह 10010110, दशमलव में 150 और हेक्स में 96 होगा। इस प्रकार, 8 के बजाय 2 वर्णों का उपयोग किया जाता है,
जिससे 75% की बचत होती है । हेक्साडेसिमल प्रतिनिधित्व में एक एकल संख्या वास्तव में 4 बिट्स से मेल खाती है। (क्योंकि 16 = 2
4. 2
n के आधार के साथ एक संख्या प्रणाली में, आप प्रत्येक संख्या में n बिट्स पैक कर सकते हैं।)
इस प्रकार, एक पूरे स्ट्रिंग को संग्रहीत करने और प्रति मूल्य एक वर्ण का उपयोग करने के बजाय, हम होशियार तरीके से जा सकते हैं और इस तरह के स्ट्रिंग को हेक्साडेसिमल संख्या में बदल सकते हैं। यह कैसे करना है? इस तरह:
parseInt('10010110', 2).toString(16);
डेटा को पठनीय रूप में कैसे लौटाया जाए? कहीं आसान नहीं है:
parseInt('96', 16).toString(2);
अब, पिछली बार की तरह, हम मानों के माध्यम से लूप कर सकते हैं और लूप का उपयोग करके उनके साथ कुछ उपयोगी कर सकते हैं।
क्या यह बेहतर करना संभव है?
वास्तव में यह संभव है! क्यों हेक्साडेसिमल संख्या प्रणाली में परिवर्तित होती है, जो 26 से लैटिन वर्णमाला के केवल 6 अक्षरों का उपयोग करती है?
Number#toString()
विधि आपको
बेस 36 का उपयोग करने की अनुमति देती है
- आधार 36 के साथ संख्या प्रणाली (
>= 37
हमें
RangeError
मिलता है), जो प्रभावी रूप से लैटिन वर्णमाला के
सभी अक्षरों का उपयोग करता है। इस प्रकार, हम 32 मानों को 6 वर्णों में संपीड़ित कर सकते हैं, जिसका अर्थ है सरल स्ट्रिंग विधि की तुलना में 81.25% बचत। कोड अभी भी सरल है:
parseInt( '1001011000', 2).toString(36);
कई वहीं रुक जाएंगे। लेकिन अधिक जिज्ञासु कहेंगे: "हमारे पास अभी भी बड़े अक्षर और अन्य प्रतीक हैं, हम अभी भी पूरी क्षमता का उपयोग नहीं करते हैं!" और वे सही होंगे। जब आप पाठ संपादक में बाइनरी फ़ाइल खोलते हैं तो यह कोई दुर्घटना नहीं है, आप स्क्रीन पर अजीब अक्षर देखते हैं, संख्याओं और अक्षरों के साथ मिश्रित - ऊपरी और निचले मामले। UTF-16 में एन्कोड किया गया प्रत्येक वर्ण 2 बाइट्स (16 बिट्स) लेता है, जिसका अर्थ है कि सही संपीड़न एल्गोरिदम का उपयोग करके, हम 93.75% की बचत प्राप्त कर सकते हैं।
समस्या यह है कि इस तरह के एल्गोरिथ्म का उपयोग करने के लिए जावास्क्रिप्ट में कोई अंतर्निहित कार्यक्षमता नहीं है, इसलिए कोड थोड़ा अधिक जटिल हो जाता है।
एक पात्र में 16 मान पैक करना
हमें
String.fromCharCode
विधि की आवश्यकता होगी। यह 65535 तक एक संख्यात्मक मान लेता है और एक चरित्र देता है (और 65535 से अधिक मूल्यों के लिए, एक खाली स्ट्रिंग लौटाता है)।
हमारी रेखा को 16 वर्णों के टुकड़ों में विभाजित करें।
आप इसे
.match(/.{1,16}/g)
साथ कर सकते
हैं । सभी कोड इस तरह दिखेगा:
function pack(/* string */ values) { var chunks = values.match(/.{1,16}/g), packed = ''; for (var i=0; i < chunks.length; i++) { packed += String.fromCharCode(parseInt(chunks[i], 2)); } return packed; } function unpack(/* string */ packed) { var values = ''; for (var i=0; i < packed.length; i++) { values += packed.charCodeAt(i).toString(2); } return values; }
इतना जटिल नहीं, है ना?
कोड की ये कुछ पंक्तियाँ आपको उपरोक्त 512 मानों को ड्रम ड्रम (
32 रोल)
(64 बाइट्स) में पैक करने की अनुमति देती हैं! मूल 2KB (एक साधारण सरणी में भंडारण के साथ) से बहुत बेहतर है, है ना?
प्रतिबंध
जावास्क्रिप्ट में संख्याएँ अपनी सीमाएँ हैं। यहां वर्णित विधियों के लिए, जिनमें संख्याओं के लिए मध्यवर्ती रूपांतरण शामिल हैं, सीमा
1023 बूलियन पर सेट है क्योंकि
parseInt('1111…1111', 2)
अधिक के साथ
Infinity
लौटाएगा। यह प्रतिबंध उत्तरार्द्ध विधि पर लागू नहीं होता है, क्योंकि हम पूरे स्ट्रिंग के बजाय बिट्स के ब्लॉक को परिवर्तित करते हैं। और, ज़ाहिर है, यह प्रतिबंध पहले दो तरीकों (सरणी और स्ट्रिंग) पर लागू नहीं होता है क्योंकि वे पैकिंग मूल्यों को बिल्कुल शामिल नहीं करते हैं।
"मुझे लगता है कि हम बहुत दूर चले गए हैं"
हां, कुछ मामलों में ऐसा अनुकूलन अनावश्यक हो सकता है। लेकिन अगर आपको सीमित स्थानों में तार्किक मूल्यों का एक गुच्छा बचाने की आवश्यकता है जो केवल तारों का समर्थन करते हैं, तो ये विधियां बहुत उपयोगी होंगी। और किसी चीज का अनुकूलन जो कि बड़ी आवृत्ति के साथ तार पर संचारित होता है, कभी नहीं होता है। उदाहरण के लिए, कुकीज़ लगभग हर अनुरोध में प्रेषित होती हैं, इसलिए उन्हें यथासंभव छोटा होना चाहिए। एक और उदाहरण ऑनलाइन मल्टीप्लेयर गेम है, जिसके लिए सर्वर की प्रतिक्रिया तेज बिजली होनी चाहिए, अन्यथा ऐसा गेम खेलना बिल्कुल भी मजेदार नहीं होगा।
और यहां तक कि अगर इस तरह का गहरा अनुकूलन आपके लिए नहीं है, तो मुझे उम्मीद है कि इस लेख ने आपको विचार के लिए कुछ भोजन दिया है और शायद आपको कुछ सिखाया है।
अनुवाद। मूल (en): जावास्क्रिप्ट के साथ हाँ / नहीं मान की लंबी सूची का अनुकूलन
मूल लेखक: ली वेरौ