जनरेटर के साथ async / प्रतीक्षा और ES6 उपज के बीच अंतर


82

मैं सिर्फ इस शानदार लेख « जनरेटर » को पढ़ रहा था और यह इस फ़ंक्शन को स्पष्ट रूप से उजागर करता है, जो जनरेटर कार्यों को संभालने के लिए एक सहायक कार्य है:

function async(makeGenerator){
  return function () {
    var generator = makeGenerator.apply(this, arguments);

    function handle(result){
      // result => { done: [Boolean], value: [Object] }
      if (result.done) return Promise.resolve(result.value);

      return Promise.resolve(result.value).then(function (res){
        return handle(generator.next(res));
      }, function (err){
        return handle(generator.throw(err));
      });
    }

    try {
      return handle(generator.next());
    } catch (ex) {
      return Promise.reject(ex);
    }
  }
}

जो मैं परिकल्पना बनाना कम या ज्यादा तरीका है asyncखोजशब्द के साथ लागू किया गया है async/ awaitतो सवाल यह है कि अगर ऐसा है, तो क्या बिल्ली awaitऔर कीवर्ड में अंतर है yield? क्या awaitहमेशा किसी वादे में कुछ बदल जाता है, जबकि yieldऐसी कोई गारंटी नहीं है? यह मेरा सबसे अच्छा अनुमान है!

आप यह भी देख सकते हैं कि इस लेख में जनरेटर के साथ कैसे async/ awaitके समान है yieldजहां वह 'स्पॉन' फ़ंक्शन ES7 async फ़ंक्शन का वर्णन करता है


1
async फ़ंक्शन -> एक coroutine। जनरेटर -> पुनरावृत्ति जो अपने आंतरिक पुनरावृत्तियों तंत्र का प्रबंधन करने के लिए एक कोरटाइन का उपयोग करता है। इंतजार एक कोरटाइन को निलंबित कर देता है, जबकि उपज एक कोरटाइन से वापस आती है जो कुछ जनरेटर का उपयोग करता है
डेविड हैम

1
async/awaitES7 का हिस्सा नहीं है। कृपया टैग विवरण पढ़ें।
फेलिक्स क्लिंग

@ दाविद हैम, हाँ, लेकिन async प्रतीक्षा जनरेटर के शीर्ष पर बनाया गया है, इसलिए वे अलग नहीं हैं
अलेक्जेंडर मिल्स

जवाबों:


46

yieldका बिल्डिंग ब्लॉक माना जा सकता है awaityieldइसके द्वारा दिया गया मान लेता है और इसे कॉलर को पास कर देता है। कॉल करने वाला फिर उस मान (1) के साथ जो चाहे कर सकता है। बाद में कॉलर जनरेटर (थ्रू generator.next()) को एक मान वापस दे सकता है जो yieldअभिव्यक्ति (2) का परिणाम बन जाता है , या एक त्रुटि जो yieldअभिव्यक्ति (3) द्वारा फेंक दी जाएगी ।

async- awaitउपयोग करने के लिए माना जा सकता है yield। At (1) कॉलर (यानी async- awaitड्राइवर - आपके द्वारा पोस्ट किए गए फ़ंक्शन के समान) एक समान एल्गोरिथ्म new Promise(r => r(value)(नोट, नहीं Promise.resolve , लेकिन यह एक बड़ी बात नहीं है) का उपयोग करके एक वादा में मूल्य लपेट देगा । यह तब हल करने के वादे की प्रतीक्षा करता है। यदि यह पूरा हो जाता है, तो यह पूरा हुआ मान वापस (2) पर आ जाता है। यदि यह अस्वीकार करता है, तो यह अस्वीकृति कारण को (3) में त्रुटि के रूप में फेंकता है।

तो async- की उपयोगिता awaitयह मशीनरी है जो yieldउपज के मूल्य को एक वादा के रूप में अनप्लग करने के लिए उपयोग करती है और अपने हल किए गए मूल्य को वापस करती है, जब तक कि फ़ंक्शन अपना अंतिम मूल्य वापस नहीं करता है।


1
इस उत्तर की जाँच करें stackoverflow.com/a/39384160/3933557 जो इस तर्क का खंडन करता है। async-wait पैदावार के समान दिखता है, लेकिन यह हुड के तहत वादों की श्रृंखला का उपयोग करता है। कृपया साझा करें यदि आपके पास कोई अच्छा संसाधन है तो "Async-wait को उपज का उपयोग करने के लिए माना जा सकता है"
समरेंद्र

1
मुझे यकीन नहीं है कि आप उस उत्तर को "इस तर्क के विपरीत" कैसे ले रहे हैं, क्योंकि यह इस उत्तर के समान ही बात कह रहा है। > इस बीच, बाबेल जैसे ट्रांसपॉयलर आपको एसिंक्स / वेट लिखने और कोड को जनरेटर में बदलने की अनुमति देते हैं।
अर्नोनियन

इसका कहना है कि बैबल जनरेटर में परिवर्तित हो जाता है, लेकिन आप जो कह रहे हैं, "उपज को प्रतीक्षा का निर्माण खंड माना जा सकता है" और "एसिंक्स-वेट को उपज का उपयोग करने के लिए माना जा सकता है।" जो मेरी समझ (सुधार के अधीन) के लिए सही नहीं है। async- प्रतीक्षित आंतरिक रूप से उस उत्तर में उल्लिखित वादा श्रृंखला का उपयोग करता है। अगर कोई चीज मुझे याद आ रही है तो मैं उसे समझना चाहता हूं, क्या आप इस पर अपने विचार साझा कर सकते हैं।
समरेंद्र

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

45

खैर, यह पता चला है कि async/ awaitऔर जनरेटर के बीच बहुत करीबी रिश्ता है । और मेरा मानना ​​है कि async/ awaitहमेशा जनरेटर पर बनाया जाएगा। यदि आप बैबिल ट्रांसपाइल्स async/ जिस तरह से देखते हैं await:

बबेल यह लेता है:

this.it('is a test', async function () {

    const foo = await 3;
    const bar = await new Promise(resolve => resolve('7'));
    const baz = bar * foo;
    console.log(baz);

});

और इसे इस में बदल देता है

function _asyncToGenerator(fn) {
    return function () {
        var gen = fn.apply(this, arguments);
        return new Promise(function (resolve, reject) {
            function step(key, arg) {
                try {
                    var info = gen[key](arg);
                    var value = info.value;
                } catch (error) {
                    reject(error);
                    return;
                }
                if (info.done) {
                    resolve(value);
                } else {
                    return Promise.resolve(value).then(function (value) {
                        return step("next", value);
                    }, function (err) {
                        return step("throw", err);
                    });
                }
            }

            return step("next");
        });
    };
}


this.it('is a test', _asyncToGenerator(function* () {   // << now it's a generator

    const foo = yield 3;    //  <<< now it's yield, not await
    const bar = yield new Promise(resolve => resolve(7));
    const baz = bar * foo;
    console.log(baz);

}));

आपने गणित कर दिया।

इससे ऐसा लगता है कि asyncकीवर्ड सिर्फ रैपर फ़ंक्शन है, लेकिन अगर ऐसा है तो awaitबस चालू हो जाता है yield, संभवत: बाद में तस्वीर में कुछ और होगा जब वे मूल निवासी हो जाएंगे।

आप इसके लिए और अधिक स्पष्टीकरण यहाँ देख सकते हैं: https://www.promisejs.org/generators/


2
NodeJS के पास कुछ समय के लिए देशी async / प्रतीक्षा है, बिना जनरेटर के: codeforgeek.com/2017/02/…
Bram

3
@ ब्रैम मूल कार्यान्वयन बिल्कुल हुड के नीचे जनरेटर का उपयोग करता है, एक ही बात, बस दूर सार।
अलेक्जेंडर मिल्स

3
मुझे ऐसा नहीं लगता। Async / wait को मूल रूप से V8 इंजन में लागू किया गया है। वे जेनरेटर जहां ES6 की सुविधा है, async / प्रतीक्षा है ES7। यह V8 इंजन (जो नोड में उपयोग किया जाता है) के 5.5 रिलीज का हिस्सा था: v8project.blogspot.nl/2016/10/v8-release-55.html । ES6 जनरेटर में ES7 async / प्रतीक्षा को ट्रांसप्लान्ट करना संभव है, लेकिन NodeJS के नए संस्करणों के साथ अब इसकी आवश्यकता नहीं है, और async / प्रतीक्षा का प्रदर्शन भी बेहतर लगता है तो जनरेटर: medium.com/@@herherhold/…
Bram

1
async / इंतजार अपने काम करने के लिए जनरेटर का उपयोग करता है
अलेक्जेंडर मिल्स

1
@AlexanderMills आप कुछ कानूनी संसाधनों को साझा कर सकते हैं, जो कहते हैं कि आंतरिक रूप से async / इंतजार का उपयोग करता है? इस ans stackoverflow.com/a/39384160/3933557 की जाँच करें जो इस तर्क का खंडन करता है। मुझे लगता है, सिर्फ इसलिए कि बैबेल जनरेटर का उपयोग करता है, इसका मतलब यह नहीं है कि यह हुड के तहत इसी तरह लागू किया जाता है। इस पर कोई विचार
समरेंद्र

28

awaitकीवर्ड और कीवर्ड के बीच क्या अंतर है yield?

awaitकीवर्ड केवल में प्रयोग की जाने वाली है async function, रों जबकि yieldकीवर्ड केवल जनरेटर में इस्तेमाल किया जा रहा है function*है। और वे स्पष्ट रूप से अलग हैं - एक रिटर्न का वादा करता है, दूसरा जनरेटर लौटाता है।

क्या awaitहमेशा किसी वादे में कुछ बदल जाता है, जबकि yieldऐसी कोई गारंटी नहीं है?

हां, प्रतीक्षित मूल्य पर awaitकॉल करेगा Promise.resolve

yield बस जनरेटर के बाहर मूल्य देता है।


एक छोटी सी नाइटी, लेकिन जैसा कि मैंने अपने जवाब में उल्लेख किया है कि प्रॉमिस का उपयोग नहीं करता है। समाधान (यह पहले इस्तेमाल किया गया था), यह प्रोमिसकैबिलिटी का उपयोग करता है :: संकल्प जो प्रोमिस कंस्ट्रक्टर द्वारा अधिक सटीक रूप से दर्शाया गया है।
अर्णवियन

@ अरनवियन: Promise.resolveबिल्कुल वही उपयोग करता है जो new PromiseCapability(%Promise%)कि एसिंक्स / वेट स्पेक सीधे उपयोग करता है, मुझे लगा कि Promise.resolveयह समझना बेहतर है।
बरगी

1
Promise.resolveएक अतिरिक्त "IsPromise == सच है? फिर समान मान लौटाएं" शॉर्ट-सर्किट जो कि async के पास नहीं है। अर्थात्, await pजहां pएक वादा है एक नया वादा लौटाएगा जो कि हल करता है p, जबकि Promise.resolve(p)वापस आ जाएगा p
अर्नवियन

ओह मैं चूक गया - मैंने सोचा कि यह केवल में Promise.castथा और स्थिरता के कारणों के लिए पदावनत किया गया था। लेकिन इससे कोई फर्क नहीं पड़ता, हम वास्तव में वैसे भी उस वादे को नहीं देखते हैं।
बेर्गी

2
var r = await p; console.log(r);: की तरह कुछ करने के लिए तब्दील किया जाना चाहिए p.then(console.log);, जबकि p: के रूप में बनाया जा सकता है var p = new Promise(resolve => setTimeout(resolve, 1000, 42));, तो यह कहने के लिए "इंतजार गलत है कॉल Promise.resolve", यह है कि आह्वान कुछ अन्य कोड पूरी तरह से दूर 'इंतजार' अभिव्यक्ति से दूर है Promise.resolve, इसलिए बदल awaitअभिव्यक्ति , यानी Promise.then(console.log)लागू किया जाएगा और प्रिंट आउट लिया जाएगा 42
देजुवु

16

tl; डॉ

उपयोग async/ awaitजनरेटर से अधिक समय के 99%। क्यों?

  1. async/ awaitसीधे कोड्स को घोषित करने की अनुमति देने वाले सबसे आम वर्कफ़्लो की जगह कोड को घोषित करता है जैसे कि यह तुल्यकालिक था, नाटकीय रूप से इसे सरल बनाना।

  2. जेनरेटर उपयोग के मामले को समाप्त कर देते हैं, जहां आप एक-दूसरे पर निर्भर होने वाले एस्किं-ऑपरेशंस की एक श्रृंखला कहेंगे और अंततः "किया" स्थिति में होंगे। सबसे सरल उदाहरण उन परिणामों के माध्यम से होगा जो अंततः अंतिम सेट लौटाते हैं लेकिन आप केवल एक पृष्ठ को आवश्यकता के रूप में कहेंगे, न कि तुरंत उत्तराधिकार में।

  3. async/ awaitवास्तव में वादों को आसान बनाने के लिए जनरेटर के शीर्ष पर निर्मित एक अमूर्तता है।

Async / Await बनाम जनरेटर के बहुत गहराई से स्पष्टीकरण देखें


5

इस परीक्षण कार्यक्रमों को आज़माएं, जिसे मैं वादों के साथ समझता await/ समझता था async

कार्यक्रम # 1: वादों के बिना यह क्रम में नहीं चलता है

function functionA() {
    console.log('functionA called');
    setTimeout(function() {
        console.log('functionA timeout called');
        return 10;
    }, 15000);

}

function functionB(valueA) {
    console.log('functionB called');
    setTimeout(function() {
        console.log('functionB timeout called = ' + valueA);
        return 20 + valueA;
    }, 10000);
}

function functionC(valueA, valueB) {

    console.log('functionC called');
    setTimeout(function() {
        console.log('functionC timeout called = ' + valueA);
        return valueA + valueB;
    }, 10000);

}

async function executeAsyncTask() {
    const valueA = await functionA();
    const valueB = await functionB(valueA);
    return functionC(valueA, valueB);
}
console.log('program started');
executeAsyncTask().then(function(response) {
    console.log('response called = ' + response);
});
console.log('program ended');

कार्यक्रम # 2: वादों के साथ

function functionA() {
    return new Promise((resolve, reject) => {
        console.log('functionA called');
        setTimeout(function() {
            console.log('functionA timeout called');
            // return 10;
            return resolve(10);
        }, 15000);
    });   
}

function functionB(valueA) {
    return new Promise((resolve, reject) => {
        console.log('functionB called');
        setTimeout(function() {
            console.log('functionB timeout called = ' + valueA);
            return resolve(20 + valueA);
        }, 10000);

    });
}

function functionC(valueA, valueB) {
    return new Promise((resolve, reject) => {
        console.log('functionC called');
        setTimeout(function() {
            console.log('functionC timeout called = ' + valueA);
            return resolve(valueA + valueB);
        }, 10000);

    });
}

async function executeAsyncTask() {
    const valueA = await functionA();
    const valueB = await functionB(valueA);
    return functionC(valueA, valueB);
}
console.log('program started');
executeAsyncTask().then(function(response) {
    console.log('response called = ' + response);
});
console.log('program ended');

0

कई मायनों में, जनरेटर async / प्रतीक्षा का एक सुपरसेट हैं। अभी async / wait में सह की तुलना में क्लीनर स्टैक के निशान हैं , सबसे लोकप्रिय async / प्रतीक्षारत जनरेटर आधारित lib है। आप अपने स्वयं के स्वाद को लागू कर सकते हैं async / प्रतीक्षा में जनरेटर का उपयोग कर सकते हैं और नई सुविधाओं को जोड़ सकते हैं, जैसे अंतर्निहित समर्थन के लिएyield गैर-वादों के या इसे RxJS वेधशालाओं पर बनाना।

तो, संक्षेप में, जनरेटर आपको अधिक लचीलापन देते हैं और जनरेटर-आधारित कामों में आम तौर पर अधिक विशेषताएं होती हैं। लेकिन async / इंतजार भाषा का एक मुख्य हिस्सा है, यह मानकीकृत है और यह आपके तहत नहीं बदलेगा, और आपको इसका उपयोग करने के लिए किसी पुस्तकालय की आवश्यकता नहीं है। मेरे पास async / प्रतीक्षा और जनरेटर के अंतर पर अधिक विवरण के साथ एक ब्लॉग पोस्ट है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.