कई वादे कैसे वापस करें और अन्य सामान करने से पहले उन सभी की प्रतीक्षा करें


85

मेरे पास एक लूप है जो एक विधि को कॉल करता है जो सामान को अतुल्यकालिक रूप से करता है। यह लूप विधि को कई बार कॉल कर सकता है। इस लूप के बाद, मेरे पास एक और लूप है जिसे केवल तब निष्पादित करने की आवश्यकता होती है जब सभी अतुल्यकालिक सामान किया जाता है।

इसलिए यह दिखाता है कि मुझे क्या चाहिए:

for (i = 0; i < 5; i++) {
    doSomeAsyncStuff();    
}

for (i = 0; i < 5; i++) {
    doSomeStuffOnlyWhenTheAsyncStuffIsFinish();    
}

मैं वादों से बहुत परिचित नहीं हूं, इसलिए क्या कोई मुझे इसे हासिल करने में मदद कर सकता है?

यह मेरा doSomeAsyncStuff()व्यवहार है:

function doSomeAsyncStuff() {
    var editor = generateCKEditor();
    editor.on('instanceReady', function(evt) {
        doSomeStuff();
        // There should be the resolve() of the promises I think.
    })
}

शायद मुझे ऐसा कुछ करना होगा:

function doSomeAsyncStuff() {
    var editor = generateCKEditor();
    return new Promise(function(resolve,refuse) {
        editor.on('instanceReady', function(evt) {
            doSomeStuff();
            resolve(true);
        });
    });
}

लेकिन मैं वाक्य रचना के बारे में निश्चित नहीं हूं।


क्या आप अतुल्यकालिक कॉल के नियंत्रण में हैं? क्या वे पहले से ही वादे वापस करते हैं, या आप उन्हें वादे वापस कर सकते हैं?
टीजे क्राउडर

वास्तव में अनुक्रम क्या है? क्या आपको पिछले सभी एसिंक्स को समाप्त करने के बाद अन्य कार्यों को कॉल करने की आवश्यकता है ? या क्या आपको प्रत्येक async समाप्त होने के बाद बस फ़ंक्शन को कॉल करने की आवश्यकता है?
Sosdoc

अभी के लिए पहला फ़ंक्शन वादों को वापस नहीं करता है। जिसे मुझे लागू करना है। मैं अपने कार्यों के वर्कफ़्लो के कुछ विवरण जोड़ने के लिए अपने संदेश को संपादित करना चाहता हूं। और हां मुझे यह चाहिए कि दूसरे लूप में सामान को निष्पादित करने के लिए शुरू करने से पहले पहले लूप का सारा सामान खत्म हो जाए।
गैंबिन जूल

1
अपने संपादन को फिर से शुरू करें: "शायद मुझे ऐसा कुछ करना होगा" हाँ, बहुत पसंद है, सिवाय इसके कोई sअंत नहीं है Promise
टीजे क्राउडर

जवाबों:


161

आप इसके लिए Promise.all( युक्ति , एमडीएन ) का उपयोग कर सकते हैं : यह व्यक्तिगत वादों के एक समूह को स्वीकार करता है और आपको एक भी वादा वापस दिलाता है जिसे हल किया जाता है जब आप इसे दे चुके सभी को हल कर दिया जाता है, या जब उनमें से किसी को अस्वीकार कर दिया जाता है।

इसलिए यदि आप doSomeAsyncStuffएक वादा वापस करते हैं, तो:

    const promises = [];
//  ^^^^^−−−−−−−−−−−−−−−−−−−−−−−−−−− use `const` or `let`, not `var`
    
    for (let i = 0; i < 5; i++) {
//       ^^^−−−−−−−−−−−−−−−−−−−−−−−− added missing declaration
        promises.push(doSomeAsyncStuff());
    }
    
    Promise.all(promises)
        .then(() => {
            for (let i = 0; i < 5; i++) {
//               ^^^−−−−−−−−−−−−−−−− added missing declaration
                doSomeStuffOnlyWhenTheAsyncStuffIsFinish();    
            }
        })
        .catch((e) => {
            // handle errors here
        });

एमडीएन का यहां वादों पर एक लेख है । मैं अपनी पुस्तक जावास्क्रिप्ट: द न्यू टॉयज के अध्याय 8 में विस्तार से प्रस्तावना को भी शामिल करता हूं , यदि आप रुचि रखते हैं तो मेरी प्रोफाइल में लिंक।

यहाँ एक उदाहरण है:

 function doSomethingAsync(value) {
     return new Promise((resolve) => {
         setTimeout(() => {
             console.log("Resolving " + value);
             resolve(value);
         }, Math.floor(Math.random() * 1000));
     });
   }
   
   function test() {
       const promises = [];
       
       for (let i = 0; i < 5; ++i) {
           promises.push(doSomethingAsync(i));
       }
       
       Promise.all(promises)
           .then((results) => {
               console.log("All done", results);
           })
           .catch((e) => {
               // Handle errors here
           });
   }
   
   test();

नमूना उत्पादन (क्योंकि Math.random, पहले क्या खत्म हो सकता है भिन्न हो सकते हैं):

निराकरण ३
हल करना २
हल करना १
संकल्प ४
हल करना ०
सभी किया [0,1,2,3,4]

ठीक है धन्यवाद, मैं अब यह कोशिश करता हूं और मैं कुछ मिनटों में प्रतिक्रिया देता हूं।
गैंबिन जूल

12
वाह, बहुत बहुत धन्यवाद, अब मैं बहुत अधिक वादों को समझता हूं। मैं वादों के बारे में बहुत कुछ पढ़ता हूं, लेकिन जब तक हमें उन्हें वास्तविक कोड में उपयोग करने की आवश्यकता नहीं होती है, तब तक हम वास्तव में सभी तंत्रों को नहीं समझते हैं। अब मैं इसे बेहतर बनाता हूं और आप शांत सामान लिखना शुरू कर सकते हैं, धन्यवाद।
गैंबिन जूल

1
इसके अलावा, आप पूरा करने के लिए इन कार्यों (उदाहरण के मजाक प्रगति के लिए) किसी भी कारण से क्रम में प्राप्त करना चाहते हैं, तो आप बदल सकते हैं Math.floor(Math.random() * 1000)करने के लिए(i * 1000)
ठीक यकीन है कि

@TJ अब मैं परिणाम डेटा को दृश्य में कैसे प्रस्तुत कर सकता हूं और वहां मैं डेटा दिखाने के लिए लूप कर सकता हूं
अजीत सिंह

1
@ user1063287 - आप ऐसा कर सकते हैं यदि कोड एक संदर्भ में है जहां awaitअनुमति है। फिलहाल, एक ही जगह आप उपयोग कर सकते हैं awaitएक asyncफ़ंक्शन के अंदर है। (कुछ बिंदु पर आप इसे मॉड्यूल के शीर्ष स्तर पर भी उपयोग कर पाएंगे।)
टीजे क्राउडर

5

एक पुन: प्रयोज्य फ़ंक्शन इस पैटर्न के लिए अच्छी तरह से काम करता है:

function awaitAll(count, asyncFn) {
  const promises = [];

  for (i = 0; i < count; ++i) {
    promises.push(asyncFn());
  }

  return Promise.all(promises);
}

ओपी उदाहरण:

awaitAll(5, doSomeAsyncStuff)
  .then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results))
  .catch(e => console.error(e));

एक संबंधित पैटर्न, एक सरणी पर पुनरावृत्ति कर रहा है और प्रत्येक आइटम पर एक async ऑपरेशन कर रहा है:

function awaitAll(list, asyncFn) {
  const promises = [];

  list.forEach(x => {
    promises.push(asyncFn(x));
  });

  return Promise.all(promises);
}

उदाहरण:

const books = [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }];

function doSomeAsyncStuffWith(book) {
  return Promise.resolve(book.name);
}

awaitAll(books, doSomeAsyncStuffWith)
  .then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results))
  .catch(e => console.error(e));

1
यह वास्तव में कोड को समझने और क्लीनर को आसान बनाता है। मुझे नहीं लगता कि वर्तमान उदाहरण (जो स्पष्ट रूप से ओपी के कोड के अनुकूल था) यह न्याय करता है। यह एक साफ-सुथरी चाल है, धन्यवाद!
शॉन वर्माक

2
const doSomeAsyncStuff = async (funcs) => {
  const allPromises = funcs.map(func => func());
  return await Promise.all(allPromises);
}

doSomeAsyncStuff([
  () => new Promise(resolve => setTimeout(() => resolve(), 100)),
  () => new Promise(resolve => setTimeout(() => resolve(), 100)),
  () => new Promise(resolve => setTimeout(() => resolve(), 100)),
  () => new Promise(resolve => setTimeout(() => resolve(), 100)),
  () => new Promise(resolve => setTimeout(() => resolve(), 100)),
]);

1

यहाँ वह कोड है जो मैंने स्वयं के लिए लिखा था ताकि यहाँ दिए गए उत्तरों को समझ सकूँ। लूप के लिए मेरे पास प्रश्न हैं, इसलिए मैंने asyncFunctionइसका स्थान लेने के लिए यहां रखा । आशा है कि यह किसी की मदद करता है। आप इस स्क्रिप्ट को नोड या कई जावास्क्रिप्ट रनटाइम में चला सकते हैं।

let asyncFunction = function(value, callback)
{
        setTimeout(function(){console.log(value); callback();}, 1000);
}



// a sample function run without promises

asyncFunction(10,
    function()
    {
        console.log("I'm back 10");
    }
);


//here we use promises

let promisesArray = [];

let p = new Promise(function(resolve)
{
    asyncFunction(20,
        function()
        {
            console.log("I'm back 20");
            resolve(20);
        }
    );
});

promisesArray.push(p);


for(let i = 30; i < 80; i += 10)
{
    let p = new Promise(function(resolve)
    {
        asyncFunction(i,
            function()
            {
                console.log("I'm back " + i);
                resolve(i);
            }
        );
    });
    promisesArray.push(p);
}


// We use Promise.all to execute code after all promises are done.

Promise.all(promisesArray).then(
    function()
    {
        console.log("all promises resolved!");
    }
)

0

/*** Worst way ***/
for(i=0;i<10000;i++){
  let data = await axios.get(
    "https://yourwebsite.com/get_my_data/"
  )
  //do the statements and operations
  //that are dependant on data
}

//Your final statements and operations
//That will be performed when the loop ends

//=> this approach will perform very slow as all the api call
// will happen in series


/*** One of the Best way ***/

const yourAsyncFunction = async (anyParams) => {
  let data = await axios.get(
    "https://yourwebsite.com/get_my_data/"
  )
  //all you statements and operations here
  //that are dependant on data
}
var promises = []
for(i=0;i<10000;i++){
  promises.push(yourAsyncFunction(i))
}
await Promise.all(promises)
//Your final statement / operations
//that will run once the loop ends

//=> this approach will perform very fast as all the api call
// will happen in parallal

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