यह एक नए साल की शुरुआत है, और जबकि बहुत से लोग अधिक सक्रिय होने का वादा कर रहे हैं, मैं आपको दिखाने जा रहा हूं कि कैसे Promise
को और अधिक आलसी बनाया जाए...Promise
एस, वह है।
यह एक पल में और अधिक समझ में आएगा।
सबसे पहले, आइए बुनियादी Promise
उदाहरण देखें। यहां, मेरे पास नींद नामक एक फ़ंक्शन है जो मिलीसेकंड और एक मान में समय लेता है। यह एक वादा देता है जो मिलीसेकंड की संख्या के लिए एक setTimeout
निष्पादित करेगा जिसे हमें इंतजार करना चाहिए; तब वादा मूल्य के साथ हल हो जाता है।
/** * @template ValueType * @param {number} ms * @param {ValueType} value * @returns {Promise<ValueType>} */ function sleep(ms, value) { return new Promise((resolve) => { setTimeout(() => resolve(value), ms); }); }
यह इस तरह काम करता है:
हम 1000
और 'Yawn & stretch'
के तर्कों के साथ sleep
फंक्शन का इंतजार कर सकते हैं, और एक सेकंड के बाद, console
'यॉन एंड स्ट्रेच' स्ट्रिंग को लॉग करेगा।
इसमें कुछ भी खास नहीं है। यह शायद वैसा ही व्यवहार करता है जैसा आप उम्मीद करेंगे, लेकिन यह थोड़ा अजीब हो जाता है अगर हम इसे बाद में await
करने के लिए एक चर के रूप में संग्रहीत करते हैं, बजाय इसके कि तुरंत लौटाए गए Promise
का await
करें।
const nap = sleep(1000, 'Yawn & stretch')
अब, मान लें कि हम कोई अन्य कार्य करते हैं जिसमें समय लगता है (जैसे अगला उदाहरण टाइप करना), और फिर nap
चर await
करें।
हल करने से पहले आप एक सेकंड की देरी की उम्मीद कर सकते हैं, लेकिन वास्तव में, यह तुरंत हल हो जाता है। जब भी आप एक Promise
बनाते हैं, तो आप इसके लिए जिम्मेदार किसी भी अतुल्यकालिक कार्यक्षमता को तुरंत चालू कर देते हैं।
हमारे उदाहरण में, जिस क्षण हम nap
वेरिएबल को परिभाषित करते हैं, Promise
बन जाता है जो setTimeout
को निष्पादित करता है। क्योंकि मैं धीमा टाइपर हूं, जब तक हम इसका await
करेंगे, तब तक Promise
हल हो जाएगा।
दूसरे शब्दों में, Promise
एस उत्सुक हैं। वे आपकी प्रतीक्षा करने के लिए आपकी await
नहीं करते हैं।
कुछ मामलों में, यह अच्छी बात है। अन्य मामलों में, यह अनावश्यक संसाधन उपयोग को जन्म दे सकता है। उन परिदृश्यों के लिए, आप ऐसा कुछ चाहते हैं जो Promise
जैसा दिखता हो, लेकिन उपयोग करता हो
इससे पहले कि हम आगे बढ़ें, मैं आपको कुछ दिलचस्प दिखाना चाहता हूँ।
Promise
केवल ऐसी चीजें नहीं हैं जिन्हें जावास्क्रिप्ट में await
किया जा सकता है। यदि हम एक .then()
विधि के साथ एक सादा Object
बनाते हैं, तो हम वास्तव में किसी भी Promise
की तरह ही उस वस्तु await
कर सकते हैं।
यह एक तरह से अजीब है, लेकिन यह हमें अलग-अलग ऑब्जेक्ट बनाने की भी अनुमति देता है जो Promise
की तरह दिखते हैं, लेकिन हैं नहीं। इन वस्तुओं को कभी-कभी "कहा जाता है"
इसे ध्यान में रखते हुए, आइए एक नया बनाएंLazyPromise
कहा जाता है जो बिल्ट-इन Promise
कंस्ट्रक्टर का विस्तार करता है। विस्तार वादा सख्ती से जरूरी नहीं है, लेकिन यह instanceof
जैसी चीजों का उपयोग करके इसे Promise
के समान दिखाई देता है।
class LazyPromise extends Promise { /** @param {ConstructorParameters<PromiseConstructor>[0]} executor */ constructor(executor) { super(executor); if (typeof executor !== 'function') { throw new TypeError(`LazyPromise executor is not a function`); } this._executor = executor; } then() { this.promise = this.promise || new Promise(this._executor); return this.promise.then.apply(this.promise, arguments); } }
ध्यान केंद्रित करने वाला हिस्सा then()
विधि है। यह वास्तविक Promise
बनाने से पहले .then()
विधि निष्पादित होने तक प्रतीक्षा करने के लिए मानक Promise
के डिफ़ॉल्ट व्यवहार को हाइजैक करता है।
जब तक आप वास्तव में इसके लिए कॉल नहीं करते हैं, तब तक एसिंक्रोनस कार्यक्षमता को तुरंत चालू करने से बचा जाता है। और यह काम करता है कि क्या आप स्पष्ट रूप से .then()
को कॉल करते हैं या await
का उपयोग करते हैं।
अब देखते हैं कि क्या होता है यदि हम मूल sleep
फंक्शन में LazyPromise
के साथ Promise
को बदल दें। एक बार फिर, हम परिणाम को एक nap
वेरिएबल को असाइन करेंगे।
function sleep(ms, value) { return new LazyPromise((resolve) => { setTimeout(() => resolve(value), ms); }); } const nap = sleep(1000, 'Yawn & stretch')
फिर हम अपना समय await nap
लाइन को टाइप करने और उसे निष्पादित करने में लगाते हैं।
इस बार, हम Promise
पूरा होने से पहले एक सेकंड की देरी देखते हैं, भले ही वेरिएबल बनाए जाने के बाद कितना समय बीत चुका हो।
(ध्यान दें कि यह कार्यान्वयन केवल एक बार नया Promise
बनाता है और इसे बाद की कॉल में संदर्भित करता है। इसलिए यदि हम इसे फिर से await
करते हैं, तो यह किसी भी सामान्य Promise
की तरह तुरंत हल हो जाएगा)
बेशक, यह एक मामूली उदाहरण है कि आप शायद उत्पादन कोड में नहीं पाएंगे, लेकिन ऐसी कई परियोजनाएं हैं जो आलसी-मूल्यांकन किए गए Promise
-जैसी वस्तुओं का उपयोग करती हैं। संभवतः सबसे आम उदाहरण डेटाबेस ORM s और क्वेरी बिल्डर्स जैसे हैं
नीचे छद्म कोड पर विचार करें। यह इनमें से कुछ क्वेरी बिल्डरों से प्रेरित है:
const query = db('user') .select('name') .limit(10) const users = await query
हम एक डेटाबेस क्वेरी बनाते हैं जो "user"
तालिका में जाती है और पहली दस प्रविष्टियों का चयन करती है और उनके नाम लौटाती है। सिद्धांत रूप में, यह एक नियमित Promise
के साथ ठीक काम करेगा।
लेकिन क्या होगा अगर हम क्वेरी स्ट्रिंग पैरामीटर जैसी कुछ शर्तों के आधार पर क्वेरी को संशोधित करना चाहते हैं? Promise
का इंतजार करने से पहले क्वेरी को संशोधित करना जारी रखना अच्छा होगा।
const query = db('user') .select('name') .limit(10) if (orderBy) { query.orderBy(orderBy) } if (limit) { query.limit(limit) } if (id) { query.where({ id: id }) } const users = await query
यदि मूल डेटाबेस क्वेरी एक मानक Promise
था, तो जैसे ही हमने वेरिएबल असाइन किया, यह उत्सुकता से क्वेरी को तुरंत चालू कर देगा, और हम इसे बाद में संशोधित नहीं कर पाएंगे।
आलसी मूल्यांकन के साथ, हम इस तरह का कोड लिख सकते हैं जिसका पालन करना आसान है, डेवलपर अनुभव में सुधार करता है, और केवल एक बार क्वेरी को निष्पादित करता है जब हमें इसकी आवश्यकता होती है।
यह एक उदाहरण है जहां आलसी मूल्यांकन बहुत अच्छा है। यह HTTP अनुरोधों को बनाने, संशोधित करने और ऑर्केस्ट्रेट करने जैसी चीज़ों के लिए भी उपयोगी हो सकता है।
लेज़ी Promise
सही उपयोग के मामलों के लिए बहुत अच्छे हैं, लेकिन यह कहना नहीं है कि उन्हें हर Promise
को बदलना चाहिए। कुछ मामलों में, उत्सुकता से तत्काल करना और जितनी जल्दी हो सके प्रतिक्रिया तैयार करना फायदेमंद होता है।
यह उन "यह निर्भर करता है" परिदृश्यों में से एक है। लेकिन अगली बार जब कोई आपसे कोई Promise
करने के लिए कहे, तो इसके बारे में आलसी होने पर विचार करें।
पढ़ने के लिए आपको बहुत बहुत शुक्रिया। अगर आपको यह लेख पसंद आया हो तो प्लीज
मूल रूप से पर प्रकाशित किया गया