जावास्क्रिप्ट में एसिंक्रोनस प्रोग्रामिंग: कॉलबैक से async/await तक
\n\nजावास्क्रिप्ट एक सिंगल-थ्रेडेड भाषा है, लेकिन इसका निष्पादन मॉडल मुख्य थ्रेड को ब्लॉक किए बिना हजारों एक साथ संचालन को कुशलतापूर्वक संभालने की अनुमति देता है। यह एसिंक्रोनस प्रोग्रामिंग के कारण संभव है। Node.js में, जहां इनपुट-आउटपुट संचालन (फ़ाइलें पढ़ना, डेटाबेस क्वेरी, नेटवर्क कॉल) 90% समय लेते हैं, एसिंक्रोनसिटी को समझना एक महत्वपूर्ण कौशल बन जाता है। इस गाइड में, हम एसिंक्रोनसिटी के साथ काम करने के तीन विकासवादी चरणों का विश्लेषण करेंगे: कॉलबैक, प्रॉमिस और async/await, साथ ही Event Loop के अंदर की कार्यप्रणाली पर भी नज़र डालेंगे।
\n\n1. कॉलबैक (Callbacks): एसिंक्रोनसिटी की नींव
\n\nकॉलबैक एक फ़ंक्शन है जिसे किसी अन्य फ़ंक्शन में तर्क के रूप में पास किया जाता है और एसिंक्रोनस ऑपरेशन पूरा होने के बाद कॉल किया जाता है। यह जावास्क्रिप्ट में सबसे पुराना और सबसे बुनियादी पैटर्न है। Node.js में, कई बिल्ट-इन मॉड्यूल (fs, http) कॉलबैक का उपयोग करते हैं।
\n\nकॉलबैक के साथ फ़ाइल पढ़ने का उदाहरण:
\n\nconst fs = require('fs');\n\nconsole.log('फ़ाइल पढ़ना शुरू कर रहे हैं...');\n\nfs.readFile('example.txt', 'utf8', (err, data) => {\n if (err) {\n console.error('त्रुटि:', err);\n return;\n }\n console.log('फ़ाइल की सामग्री:', data);\n});\n\nconsole.log('कोड आगे निष्पादित हो रहा है...');\n\n\nकंसोल आउटपुट दिखाएगा कि "कोड आगे निष्पादित हो रहा है..." फ़ाइल की सामग्री से पहले दिखाई देगा। यह नॉन-ब्लॉकिंग व्यवहार है: मुख्य थ्रेड पढ़ने के पूरा होने की प्रतीक्षा नहीं करता, बल्कि निष्पादन जारी रखता है।
\n\nकॉलबैक की समस्या: Callback Hell
\nनेस्टेड एसिंक्रोनस ऑपरेशन में, कोड "नारकीय पिरामिड" में बदल जाता है:
\n\nfs.readFile('user.json', (err, userData) => {\n if (err) throw err;\n const user = JSON.parse(userData);\n db.query(`SELECT * FROM posts WHERE user_id=${user.id}`, (err, posts) => {\n if (err) throw err;\n fs.writeFile('user_posts.json', JSON.stringify(posts), (err) => {\n if (err) throw err;\n console.log('हो गया!');\n });\n });\n});\n\n\nऐसे कोड को पढ़ना, डीबग करना और बनाए रखना मुश्किल है। समाधान प्रॉमिस है।
\n\n2. प्रॉमिस (Promises): चेन और त्रुटि प्रबंधन
\n\nPromise एक ऑब्जेक्ट है जो एसिंक्रोनस ऑपरेशन के भविष्य के परिणाम का प्रतिनिधित्व करता है। यह तीन अवस्थाओं में से एक में हो सकता है: pending (प्रतीक्षा), fulfilled (सफलतापूर्वक पूर्ण) या rejected (त्रुटि के साथ अस्वीकृत)।
\n\nएक सरल प्रॉमिस बनाना:
\n\nconst readFilePromise = (filename) => {\n return new Promise((resolve, reject) => {\n fs.readFile(filename, 'utf8', (err, data) => {\n if (err) {\n reject(err);\n } else {\n resolve(data);\n }\n });\n });\n};\n\nreadFilePromise('example.txt')\n .then(data => console.log('डेटा:', data))\n .catch(err => console.error('त्रुटि:', err));\n\n\nप्रॉमिस की चेन (Chaining)
\nमुख्य लाभ बिना नेस्टिंग के अनुक्रमिक संचालन बनाने की क्षमता है:
\n\nreadFilePromise('user.json')\n .then(userData => {\n const user = JSON.parse(userData);\n return dbQueryPromise(`SELECT * FROM posts WHERE user_id=${user.id}`);\n })\n .then(posts => {\n return writeFilePromise('user_posts.json', JSON.stringify(posts));\n })\n .then(() => console.log('हो गया!'))\n .catch(err => console.error('चेन में त्रुटि:', err));\n\n\nसमानांतर निष्पादन: Promise.all
\nजब एक साथ कई स्वतंत्र संचालन करने की आवश्यकता हो:
\n\nconst promise1 = readFilePromise('file1.txt');\nconst promise2 = readFilePromise('file2.txt');\nconst promise3 = readFilePromise('file3.txt');\n\nPromise.all([promise1, promise2, promise3])\n .then(results => {\n console.log('सभी फ़ाइलें पढ़ी गईं:', results);\n })\n .catch(err => console.error('एक प्रॉमिस विफल हुआ:', err));\n\n\nPromise.all तभी सफलतापूर्वक पूरा होता है जब सभी प्रॉमिस सफलतापूर्वक निष्पादित हों। यदि कम से कम एक विफल होता है, तो यह ट्रिगर होता है