जावास्क्रिप्ट अनुप्रयोगों के प्रदर्शन का अनुकूलन: व्यावहारिक रूप से
\n\nजावास्क्रिप्ट अनुप्रयोगों का प्रदर्शन केवल एक अच्छा बोनस नहीं है, बल्कि एक महत्वपूर्ण कारक है जो उपयोगकर्ता अनुभव (UX), रूपांतरण और बुनियादी ढांचे की लागत को प्रभावित करता है। धीमी पेज लोडिंग या API प्रतिक्रिया में देरी आपको 40% तक ट्रैफ़िक खर्च कर सकती है। इस लेख में, हम JavaScript (Node.js वातावरण में) कोड को अनुकूलित करने के व्यावहारिक तरीकों पर विचार करेंगे जो आपके एप्लिकेशन को तेज़ और अधिक कुशल बनाने में मदद करेंगे। हम Event Loop के सैद्धांतिक आधारों में गहराई से नहीं जाएंगे, बल्कि सीधे उदाहरणों के साथ विशिष्ट तकनीकों पर आगे बढ़ेंगे।
\n\n1. कैशिंग: सर्वर पर लोड कम करना
\n\nएप्लिकेशन को गति देने के सबसे प्रभावी तरीकों में से एक महंगे संचालन को बार-बार करने से बचना है। कैशिंग आपको गणना या डेटाबेस क्वेरी के परिणाम को सहेजने और बार-बार अनुरोध करने पर इसे वापस करने की अनुमति देता है।
\n\nMap का उपयोग करके In-memory कैशिंग
\nसरल परिदृश्यों के लिए, जहां डेटा को जटिल अमान्यकरण तर्क की आवश्यकता नहीं होती है, अंतर्निहित Map ऑब्जेक्ट आदर्श है। यह Object से तेज़ है और कुंजियों को बार-बार जोड़ने और हटाने के लिए बेहतर अनुकूल है।
const cache = new Map();\n\nasync function fetchUserData(userId) {\n if (cache.has(userId)) {\n console.log('कैश से लौट रहे हैं');\n return cache.get(userId);\n }\n\n // DB के लिए महंगे अनुरोध का अनुकरण\n const data = await new Promise((resolve) => {\n setTimeout(() => resolve({ id: userId, name: `User_${userId}` }), 1000);\n });\n\n cache.set(userId, data);\n return data;\n}\n\n// पहला कॉल (1 सेकंड प्रतीक्षा करें)\nconsole.time('first');\nawait fetchUserData(1);\nconsole.timeEnd('first');\n\n// दूसरा कॉल (तुरंत)\nconsole.time('second');\nawait fetchUserData(1);\nconsole.timeEnd('second');\n\n\nTTL (Time-To-Live) कैश
\nकैश को पुराना होने से बचाने के लिए, आपको रिकॉर्ड का जीवनकाल जोड़ना होगा। आइए एक सरल TTL कैश लागू करें।
\n\nclass TTLMap {\n constructor(ttlMs = 60000) {\n this.ttl = ttlMs;\n this.store = new Map();\n }\n\n set(key, value) {\n const record = { value, expiry: Date.now() + this.ttl };\n this.store.set(key, record);\n }\n\n get(key) {\n const record = this.store.get(key);\n if (!record) return null;\n if (Date.now() > record.expiry) {\n this.store.delete(key);\n return null;\n }\n return record.value;\n }\n}\n\nconst userCache = new TTLMap(5000); // 5 सेकंड के लिए कैश\n\n\n2. एसिंक्रोनसिटी और Event Loop अनुकूलन
\n\nNode.js सिंगल-थ्रेडेड है, लेकिन इसकी एसिंक्रोनस प्रकृति कई अनुरोधों को कुशलतापूर्वक संसाधित करने की अनुमति देती है। प्रदर्शन का मुख्य दुश्मन सिंक्रोनस ऑपरेशन हैं जो Event Loop को ब्लॉक करते हैं।
\n\nफ़ंक्शन के सिंक्रोनस संस्करणों से बचें
\nfs, crypto और अन्य मॉड्यूल में सिंक्रोनस एनालॉग हैं (readFileSync, crypto.pbkdf2Sync)। उनका उपयोग केवल एप्लिकेशन इनिशियलाइज़ेशन के दौरान करें। अनुरोध हैंडलर के अंदर, केवल एसिंक्रोनस संस्करणों का उपयोग करें।
// खराब: Event Loop को ब्लॉक करता है\nconst data = fs.readFileSync('/path/to/file.txt', 'utf-8');\n\n// अच्छा: एसिंक्रोनस रूप से\nconst data = await fs.promises.readFile('/path/to/file.txt', 'utf-8');\n\n\nsetImmediate के साथ भारी कार्यों को विभाजित करें
\nयदि आपके पास एक भारी सिंक्रोनस लूप है (उदाहरण के लिए, 10 मिलियन तत्वों की एक सरणी को संसाधित करना), तो यह सर्वर को कुछ सेकंड के लिए ब्लॉक कर देगा। कार्य को भागों में विभाजित करें और setImmediate का उपयोग करें ताकि Event Loop भागों के बीच अन्य अनुरोधों को संसाधित कर सके।
function processLargeArray(items, chunkSize = 1000) {\n let index = 0;\n\n function processChunk() {\n const chunk = items.slice(index, index + chunkSize);\n // भाग को संसाधित करें\n chunk.forEach(item => heavyOperation(item));\n\n index += chunkSize;\n if (index < items.length) {\n // Event Loop के अगले पुनरावृत्ति पर जारी रखें\n