Async/await forEach में: एसिंक्रोनस को लूप के साथ जोड़ने का तरीका

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

आपका async/await forEach में काम क्यों नहीं करता? पहली नज़र में समझें

\n\n

क्या आपने कभी ऐसा कोड लिखा है, उम्मीद करते हुए कि वह एसिंक्रोनस ऑपरेशन को क्रम से चलाएगा?

\n\n
const users = ['alice', 'bob', 'charlie'];\n\nusers.forEach(async (user) => {\n  const data = await fetch(`https://api.example.com/users/${user}`);\n  console.log(await data.json());\n});\n\nconsole.log('हो गया!');
\n\n

और आपको "हो गया!" डेटा लोड होने से पहले ही मिल गया? परिचित लग रहा है? आप अकेले नहीं हैं। Stack Overflow पर यह सबसे लोकप्रिय सवालों में से एक है, जिसे हज़ारों बार देखा गया है। समस्या यह है कि forEach एक सिंक्रोनस मेथड है। यह सिर्फ कॉलबैक को चलाता है, लेकिन उनके पूरा होने का इंतज़ार नहीं करता। आपके async फंक्शन शुरू होते हैं, लेकिन forEach आगे बढ़ जाता है, जैसे कोई धावक जिसे दूसरों की परवाह नहीं।

\n\n

इस लेख में हम सिर्फ यह नहीं दिखाएंगे कि इसे कैसे ठीक करें। हम समझाएंगे क्यों ऐसा होता है, और आपको तीन काम के समाधान उदाहरण सहित देंगे। आप जानेंगे कि कब Promise.all इस्तेमाल करें और कब पुराना अच्छा for...of। चलिए शुरू करते हैं!

\n\n

समस्या की जड़: forEach और Promises

\n\n

आइए हुड के नीचे झांकते हैं। JavaScript में forEach मेथड इस तरह काम करता है:

\n\n
Array.prototype.forEach = function(callback) {\n  for (let i = 0; i < this.length; i++) {\n    callback(this[i], i, this);\n  }\n};
\n\n

देखा? यह हर एलिमेंट के लिए callback को कॉल करता है, लेकिन कुछ भी रिटर्न नहीं करता। भले ही कॉलबैक Promise रिटर्न करे, forEach उसे इग्नोर कर देता है। यह इंतज़ार नहीं करता, रिजल्ट इकट्ठा नहीं करता — बस चलाता है और भूल जाता है।

\n\n

जब आप async (user) => { ... } लिखते हैं, तो आपका फंक्शन Promise रिटर्न करता है। लेकिन forEach को पता नहीं कि उसके साथ क्या करना है। नतीजतन, सभी रिक्वेस्ट समानांतर में चलती हैं (अगर fetch है), लेकिन आप उनके पूरा होने का इंतज़ार नहीं कर सकते। forEach के बाद का कोड तुरंत चलता है।

\n\n

वास्तविक उदाहरण: प्रैक्टिस में यह कैसा दिखता है

\n\n

मान लीजिए आप प्रोडक्ट ID की एक array प्रोसेस कर रहे हैं और हर एक के लिए डेटाबेस से कीमत लानी है:

\n\n
const productIds = [101, 102, 103];\n\nasync function getPrice(id) {\n  // DB क्वेरी का अनुकरण\n  return new Promise(resolve => {\n    setTimeout(() => {\n      resolve(`${id} की कीमत: $${Math.floor(Math.random() * 100)}`);\n    }, 1000);\n  });\n}\n\nproductIds.forEach(async (id) => {\n  const price = await getPrice(id);\n  console.log(price);\n});\n\nconsole.log('सभी कीमतें लोड हो गईं!'); // 3 सेकंड के बजाय तुरंत चलेगा
\n\n

कंसोल में परिणाम:

\n
सभी कीमतें लोड हो गईं!\n101 की कीमत: $42\n102 की कीमत: $78\n103 की कीमत: $15
\n\n

मानिए, यह वैसा नहीं है जैसा हमने उम्मीद की थी। अच्छी खबर: इसके सरल और सुंदर समाधान हैं।

\n\n

समाधान #1: for...of — क्रमिक निष्पादन

\n\n

लूप में async/await को काम कराने का सबसे आसान तरीका है for...of का उपयोग करना। forEach के विपरीत, for...of async/await के साथ नेटिव रूप से काम करता है, क्योंकि आप ब्लॉक के अंदर एक्ज़ीक्यूशन फ्लो को कंट्रोल करते हैं।

\n\n
const productIds = [101, 102, 103];\n\nasync function getPrice(id) {\n  return new Promise(resolve => {\n    setTimeout(() => {\n      resolve(`${id} की कीमत: $${Math.floor(Math.random() * 100)}`);\n    }, 1000);\n  });\n}\n\nasync function loadAllPrices() {\n  for (const id of productIds) {\n    const price = await getPrice(id);\n    console.log(price);\n  }\n  console.log('सभी कीमतें लोड हो गईं!');\n}\n\nloadAllPrices();
\n\n

अब परिणाम इस प्रकार होगा:

\n
101 की कीमत: $42\n(1 सेकंड बाद)\n102 की कीमत: $78\n(1 सेकंड बाद)\n103 की कीमत: $15\n(1 सेकंड बाद)\nसभी कीमतें लोड हो गईं!
\n\n

फायदे: सरलता, पठनीयता, पूर्वानुमानित क्रम।

\n

नुकसान: धीमा — हर रिक्वेस्ट पिछले के पूरा होने का इंतज़ार करती है।

ब्लॉग

पुस्तक अनुशंसाएँ