[javascript] 많은 약속을 반환하고 다른 작업을 수행하기 전에 모두 기다리는 방법

비동기 적으로 작업을 수행하는 메서드를 호출하는 루프가 있습니다. 이 루프는 메서드를 여러 번 호출 할 수 있습니다. 이 루프 이후에는 모든 비동기 작업이 완료 될 때만 실행해야하는 또 다른 루프가 있습니다.

그래서 이것은 내가 원하는 것을 보여줍니다.

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);
        });
    });
}

그러나 구문이 확실하지 않습니다.



답변

이를 위해 Promise.all( spec , MDN )을 사용할 수 있습니다 . 여러 개의 개별 약속을 수락하고 사용자가 제공 한 모든 약속이 해결 될 때 해결되는 단일 약속을 돌려주고 그중 하나가 거부되면 거부됩니다.

따라서 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
        });

MDN에는 여기 에 약속에 대한 기사가 있습니다 . 또한 제 책 JavaScript : The New Toys의 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먼저 완료되는 내용이 다를 수 있음) :

해결 3
해결 2
해결 1
해결 4
0 해결
모두 완료 [0,1,2,3,4]


답변

재사용 가능한 함수는이 패턴에 대해 잘 작동합니다.

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

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

  return Promise.all(promises);
}

OP 예 :

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

관련 패턴은 배열을 반복하고 각 항목에 대해 비동기 작업을 수행합니다.

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));


답변

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)),
]);


답변

여기에 명시된 답변을 이해하기 위해 내가 작성한 코드가 있습니다. for 루프에 몽구스 쿼리가 있으므로 여기에을 넣어 asyncFunction대신합니다. 누구에게나 도움이되기를 바랍니다. 이 스크립트는 노드 또는 여러 Javascript 런타임에서 실행할 수 있습니다.

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!");
    }
)


답변

/*** 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


답변