`वापसी का वादा वादा` और` वापसी वादा` के बीच अंतर


106

नीचे दिए गए कोड के नमूनों को देखते हुए, क्या व्यवहार में कोई अंतर है, और, यदि हां, तो वे अंतर क्या हैं?

return await promise

async function delay1Second() {
  return (await delay(1000));
}

return promise

async function delay1Second() {
  return delay(1000);
}

जैसा कि मैं इसे समझता हूं, पहले async फ़ंक्शन में त्रुटि-हैंडलिंग होगी, और त्रुटियाँ async फ़ंक्शन के वादे से बाहर हो जाएंगी। हालांकि, दूसरे को एक कम टिक की आवश्यकता होगी। क्या ये सही है?

संदर्भ के लिए एक वादा वापस करने के लिए यह स्निपेट सिर्फ एक सामान्य कार्य है।

function delay(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

3
हाँ, मैंने अपने प्रश्न को संपादित किया क्योंकि आपने मेरे अर्थ को गलत समझा और यह वास्तव में जवाब नहीं था कि मैं क्या सोच रहा था।
21

1
@PitaJ: मेरा मानना ​​है कि आप asyncअपने दूसरे ( return promise) नमूने से हटा देना चाहते थे ।
स्टीफन क्लीयर

1
@ प्रीता: उस मामले में, आपका दूसरा उदाहरण एक वादा लौटाएगा जो एक वादे के साथ हल किया गया है। थोड़ा अलग।
स्टीफन क्लीयर

5
jakearchibald.com/2017/await-vs-return-vs-return-await एक अच्छा लेख है जो मतभेदों का सारांश देता है
sanchit

2
@StephenCleary, मैं इस पर लड़खड़ाया और सबसे पहले ठीक वैसा ही सोचा, एक वादा जो एक वादे के साथ हल किया जाता है वह यहां समझ में नहीं आता है। लेकिन जैसा कि यह बदल जाता है, promise.then(() => nestedPromise)समतल होगा और "का पालन करें" nestedPromise। दिलचस्प है कि यह C # में नेस्टेड कार्यों से अलग कैसे है, जहां हमें Unwrapयह करना होगा। एक साइड नोट पर, यह प्रतीत होता है कि await somePromise कॉल Promise.resolve(somePromise).then, बजाय somePromise.thenदिलचस्प दिलचस्प अंतर के साथ।
noseratio

जवाबों:


152

अधिकांश समय, वहाँ के बीच कोई अंतर नहीं है नमूदार returnऔर return await। दोनों संस्करणों में delay1Secondसटीक एक ही देखने योग्य व्यवहार है (लेकिन कार्यान्वयन के आधार पर, return awaitसंस्करण थोड़ी अधिक मेमोरी का उपयोग कर सकता है क्योंकि एक मध्यवर्ती Promiseऑब्जेक्ट बनाया जा सकता है)।

लेकिन, जैसा कि @PitaJ ने कहा, वहाँ एक मामले में जहां एक अंतर है: यदि returnया return awaitएक में नीडिंत है try- catchब्लॉक। इस उदाहरण पर विचार करें

async function rejectionWithReturnAwait () {
  try {
    return await Promise.reject(new Error())
  } catch (e) {
    return 'Saved!'
  }
}

async function rejectionWithReturn () {
  try {
    return Promise.reject(new Error())
  } catch (e) {
    return 'Saved!'
  }
}

पहले संस्करण में, async फ़ंक्शन अपने परिणाम को वापस करने से पहले अस्वीकार किए गए वादे का इंतजार करता है, जिससे अस्वीकृति को अपवाद में बदल दिया जाता है और catchखंड तक पहुंचा जा सकता है; इस प्रकार स्ट्रिंग "सेव्ड!" को हल करने का वादा वापस करेगा।

फ़ंक्शन का दूसरा संस्करण, हालांकि, एसिंक्स फ़ंक्शन के भीतर इसे प्रतीक्षा किए बिना सीधे खारिज किए गए वादे को वापस करता है , जिसका अर्थ है कि catchमामले को नहीं बुलाया गया है और कॉल करने वाले को इसके बजाय अस्वीकृति मिलती है।


शायद यह भी उल्लेख है कि स्टैक ट्रेस अलग होगा (यहां तक ​​कि एक कोशिश / पकड़ के बिना)? मुझे लगता है कि इस मुद्दे को लोग इस उदाहरण में सबसे अधिक बार चलाते हैं:]
बेंजामिन ग्रुएनबाउम

मैंने एक परिदृश्य में पाया है, कि return new Promise(function(resolve, reject) { })एक for...ofलूप के भीतर का उपयोग करना और फिर पाइप के पूरा होने तक प्रोग्राम के निष्पादन को रोकना नहीं है, हालांकि वांछित का उपयोग करते हुए resolve()लूप के भीतर कॉल करना । क्या बाद वाला भी वैध / सही सिंटैक्स है? क्या यह 'आशुलिपि' है ? क्या आप मुझे यह समझने में मदद कर सकते हैं कि उत्तरार्द्ध क्यों काम करता है और पूर्व नहीं करता है? संदर्भ के लिए, परिदृश्य में है की क्या यह उत्तरpipe()await new Promise(...)return await new Promise(...)solution 02
user1063287

10

जैसा कि अन्य उत्तरों में उल्लेख किया गया है, वादे को सीधे-सीधे वापस करके बुलबुला फुलाने पर मामूली प्रदर्शन लाभ होने की संभावना है - केवल इसलिए कि आपको पहले परिणाम का इंतजार नहीं करना है और फिर इसे फिर से दूसरे वादे के साथ लपेटना है। हालाँकि, अभी तक किसी ने टेल कॉल ऑप्टिमाइज़ेशन के बारे में बात नहीं की है।

टेल कॉल ऑप्टिमाइज़ेशन , या "उचित टेल कॉल" , एक तकनीक है जो दुभाषिया कॉल स्टैक का अनुकूलन करने के लिए उपयोग करता है। वर्तमान में, बहुत से रनटाइम्स अभी तक इसका समर्थन नहीं करते हैं - भले ही यह तकनीकी रूप से ईएस 6 मानक का हिस्सा है - लेकिन यह संभव है कि भविष्य में समर्थन जोड़ा जा सकता है, इसलिए आप वर्तमान में अच्छा कोड लिखकर इसके लिए तैयारी कर सकते हैं।

संक्षेप में, TCO (या PTC) एक फ़ंक्शन के लिए एक नया फ़्रेम खोलकर कॉल स्टैक को अनुकूलित करता है जो सीधे दूसरे फ़ंक्शन से वापस आ जाता है। इसके बजाय, यह एक ही फ्रेम का पुन: उपयोग करता है।

async function delay1Second() {
  return delay(1000);
}

चूँकि delay()सीधे delay1Second()पीटीसी का समर्थन करने वाले रनटाइम्स पहले delay1Second()(बाहरी फ़ंक्शन) के लिए एक फ्रेम खोलेंगे , लेकिन फिर इसके लिए एक और फ्रेम delay()(आंतरिक फ़ंक्शन) खोलने के बजाय , यह केवल उसी फ़्रेम का पुनः उपयोग करेगा जो बाहरी फ़ंक्शन के लिए खोला गया था। यह स्टैक का अनुकूलन करता है क्योंकि यह बहुत बड़े पुनरावर्ती कार्यों के साथ एक स्टैक अतिप्रवाह (हेहे) को रोक सकता है , जैसे fibonacci(5e+25),। अनिवार्य रूप से यह एक लूप बन जाता है, जो बहुत तेज होता है।

PTC केवल तभी सक्षम होता है जब आंतरिक फ़ंक्शन सीधे लौटाया जाता है। इसका उपयोग तब नहीं किया जाता है जब फ़ंक्शन का परिणाम लौटने से पहले बदल दिया जाता है, उदाहरण के लिए, यदि आपके पास था return (delay(1000) || null), या return await delay(1000)

लेकिन जैसा कि मैंने कहा, अधिकांश रनटाइम और ब्राउज़र अभी तक पीटीसी का समर्थन नहीं करते हैं, इसलिए यह शायद अब बहुत बड़ा अंतर नहीं बनाता है, लेकिन यह आपके कोड को भविष्य में प्रूफ करने के लिए चोट नहीं पहुंचा सकता है।

इस प्रश्न में और पढ़ें: Node.js: क्या एसिंक्स फ़ंक्शन में टेल कॉल के लिए अनुकूलन हैं?


2

यह उत्तर देने के लिए एक कठिन सवाल है, क्योंकि यह अभ्यास पर निर्भर करता है कि आपका ट्रांसपिलर (संभवतः babel) वास्तव में कैसे प्रस्तुत करता है async/await। जो चीजें स्पष्ट हैं, वे हैं:

  • दोनों कार्यान्वयन समान होना चाहिए, हालांकि पहले कार्यान्वयन में श्रृंखला में एक कम हो सकता है Promise

  • विशेष रूप से यदि आप अनावश्यक को छोड़ देते हैं await, तो दूसरे संस्करण को ट्रांसपिलर से किसी अतिरिक्त कोड की आवश्यकता नहीं होगी, जबकि पहले एक करता है।

इसलिए एक कोड प्रदर्शन और डिबगिंग के नजरिए से, दूसरा संस्करण बेहतर है, हालांकि यह केवल बहुत थोड़ा है, जबकि पहले संस्करण में थोड़ी सुगमता है, इसमें यह स्पष्ट रूप से इंगित करता है कि यह एक वादा लौटाता है।


कार्य समान क्यों होंगे? पहला लौटाया गया मान ( undefined) और दूसरा प्रतिफल a Promise
अमित

4
@ दोनों कार्य
PitaJ

एसीके। यही कारण है कि मैं बर्दाश्त नहीं कर सकता async/await- मुझे इसके बारे में तर्क करना बहुत मुश्किल है। @PJJ सही है, दोनों कार्य एक वादा वापस करते हैं।
21-22 बजे nrabinowitz

क्या होगा अगर मैं एक साथ दोनों async कार्यों के शरीर को घेर रहा था try-catch? में return promiseमामला है, किसी भी rejection, पकड़ा जाएगा नहीं किया जा सही है, जबकि, में return await promiseमामला है, यह सही हो सकता है?
PitaJ

दोनों एक वादा वापस करते हैं, लेकिन पहला "वादा" एक आदिम मूल्य, और दूसरा "वादा" एक वादा करता है। यदि आप awaitइनमें से प्रत्येक को किसी कॉल साइट पर रखते हैं, तो परिणाम बहुत भिन्न होगा।
अमित

0

यहाँ मैं आपके लिए कुछ कोड व्यावहारिक छोड़ सकता हूँ जो इसे अलग पहचान दे सकता है

 let x = async function () {
  return new Promise((res, rej) => {
    setTimeout(async function () {
      console.log("finished 1");
      return await new Promise((resolve, reject) => { // delete the return and you will see the difference
        setTimeout(function () {
          resolve("woo2");
          console.log("finished 2");
        }, 5000);
      });
      res("woo1");
    }, 3000);
  });
};

(async function () {
  var counter = 0;
  const a = setInterval(function () { // counter for every second, this is just to see the precision and understand the code
    if (counter == 7) {
      clearInterval(a);
    }

    console.log(counter);
    counter = counter + 1;
  }, 1000);
  console.time("time1");
  console.log("hello i starting first of all");
  await x();
  console.log("more code...");
  console.timeEnd("time1");
})();

फ़ंक्शन "x" सिर्फ एक फ़ंक्शन है async से यह अन्य fucn है अगर वापसी को हटा देगा यह "अधिक कोड ..."

चर x सिर्फ एक अतुल्यकालिक फ़ंक्शन है जो बदले में एक और अतुल्यकालिक फ़ंक्शन है, कोड के मुख्य में हम चर x के फ़ंक्शन को कॉल करने के लिए एक प्रतीक्षा आमंत्रित करते हैं, जब यह पूरा हो जाता है तो यह कोड के अनुक्रम का अनुसरण करता है, जो सामान्य होगा "async / प्रतीक्षा" के लिए, लेकिन x फ़ंक्शन के अंदर एक और अतुल्यकालिक फ़ंक्शन है, और यह एक वादा लौटाता है या "वादा" लौटाता है, यह x फ़ंक्शन के अंदर रहेगा, मुख्य कोड को भूल जाएगा, अर्थात यह प्रिंट नहीं करेगा। "कंसोल.लॉग (" अधिक कोड .. "), दूसरी ओर अगर हम" वेट "डालते हैं तो यह हर उस फ़ंक्शन का इंतजार करेगा जो पूरा होता है और अंत में मुख्य कोड के सामान्य अनुक्रम का अनुसरण करता है।

"कंसोल.लॉग" ("समाप्त 1" के नीचे "रिटर्न" हटाएं, आप व्यवहार देखेंगे।


1
हालांकि यह कोड प्रश्न को हल कर सकता है, जिसमें यह भी बताया गया है कि यह समस्या कैसे और क्यों हल करती है, इससे वास्तव में आपके पोस्ट की गुणवत्ता को बेहतर बनाने में मदद मिलेगी, और संभवत: अधिक वोटों का परिणाम होगा। याद रखें कि आप भविष्य में पाठकों के लिए सवाल का जवाब दे रहे हैं, न कि केवल उस व्यक्ति से जो अब पूछ रहा है। कृपया स्पष्टीकरण जोड़ने के लिए अपने उत्तर को संपादित करें और संकेत दें कि क्या सीमाएँ और मान्यताएँ लागू होती हैं।
ब्रायन

0

यहां एक टाइपस्क्रिप्ट उदाहरण है जिसे आप चला सकते हैं और अपने आप को समझा सकते हैं कि आपको "वापसी की प्रतीक्षा" की आवश्यकता है

async function  test() {
    try {
        return await throwErr();  // this is correct
        // return  throwErr();  // this will prevent inner catch to ever to be reached
    }
    catch (err) {
        console.log("inner catch is reached")
        return
    }
}

const throwErr = async  () => {
    throw("Fake error")
}


void test().then(() => {
    console.log("done")
}).catch(e => {
    console.log("outer catch is reached")
});


0

ध्यान देने योग्य अंतर: विभिन्न स्थानों पर वादा अस्वीकृति को नियंत्रित किया जाता है

  • return somePromiseकॉल साइट पर somePromise पास करेगा , और await somePromise कॉल साइट पर बसने के लिए (यदि कोई हो)। इसलिए, अगर कुछ प्रॉमिस को खारिज कर दिया जाता है, तो इसे स्थानीय कैच ब्लॉक से नहीं बल्कि कॉल साइट के कैच ब्लॉक से नियंत्रित किया जाएगा।

async function foo () {
  try {
    return Promise.reject();
  } catch (e) {
    console.log('IN');
  }
}

(async function main () {
  try {
    let a = await foo();
  } catch (e) {
    console.log('OUT');
  }
})();
// 'OUT'

  • return await somePromiseपहले स्थानीय स्तर पर बसने के लिए somePromise का इंतजार करेंगे । इसलिए, मूल्य या अपवाद पहले स्थानीय स्तर पर नियंत्रित किया जाएगा। => somePromiseअस्वीकार किए जाने पर स्थानीय कैच ब्लॉक निष्पादित किया जाएगा ।

async function foo () {
  try {
    return await Promise.reject();
  } catch (e) {
    console.log('IN');
  }
}

(async function main () {
  try {
    let a = await foo();
  } catch (e) {
    console.log('OUT');
  }
})();
// 'IN'

कारण: return await Promiseस्थानीय और बाहर दोनों का इंतजार करता है, return Promiseकेवल बाहर का इंतजार करता है

विस्तृत चरण:

वापसी वादा

async function delay1Second() {
  return delay(1000);
}
  1. पुकार delay1Second();
const result = await delay1Second();
  1. अंदर delay1Second(), फ़ंक्शन delay(1000)तुरंत के साथ एक वादा लौटाता है [[PromiseStatus]]: 'pending। चलो इसे बुलाओ delayPromise
async function delay1Second() {
  return delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
}
  1. Async फ़ंक्शंस उनके रिटर्न मान को अंदर Promise.resolve()( स्रोत ) से लपेटेंगे । क्योंकि delay1Secondएक async फ़ंक्शन है, हमारे पास:
const result = await Promise.resolve(delayPromise); 
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
  1. Promise.resolve(delayPromise)delayPromiseकुछ भी किए बिना रिटर्न देता है क्योंकि इनपुट पहले से ही एक वादा है ( MDN Promise.resolve देखें ):
const result = await delayPromise; 
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
  1. awaitdelayPromiseबसने तक इंतजार करता है।
  • IF delayPromise, PromiseValue = 1 के साथ पूरा हुआ है:
const result = 1; 
  • ईएलएसई delayPromiseखारिज कर दिया है:
// jump to catch block if there is any

वापसी का वादा

async function delay1Second() {
  return await delay(1000);
}
  1. पुकार delay1Second();
const result = await delay1Second();
  1. अंदर delay1Second(), फ़ंक्शन delay(1000)तुरंत के साथ एक वादा लौटाता है [[PromiseStatus]]: 'pending। चलो इसे बुलाओ delayPromise
async function delay1Second() {
  return await delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
}
  1. स्थानीय प्रतीक्षालय का इंतजार होने तक इंतजार किया जाएगा delayPromise
  • केस 1 : delayPromisePromiseValue = 1 के साथ पूरा हुआ:
async function delay1Second() {
  return 1;
}
const result = await Promise.resolve(1); // let's call it "newPromise"
const result = await newPromise; 
// newPromise.[[PromiseStatus]]: 'resolved'
// newPromise.[[PromiseValue]]: 1
const result = 1; 
  • केस 2 : delayPromiseखारिज कर दिया गया है:
// jump to catch block inside `delay1Second` if there is any
// let's say a value -1 is returned in the end
const result = await Promise.resolve(-1); // call it newPromise
const result = await newPromise;
// newPromise.[[PromiseStatus]]: 'resolved'
// newPromise.[[PromiseValue]]: -1
const result = -1;

शब्दावली:

  • रुकना: Promise.[[PromiseStatus]]से परिवर्तन pendingकरने के लिए resolvedयाrejected
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.