Javascript 如何在循环中返回许多 Promise 并等待它们全部执行其他操作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31426740/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 06:42:02  来源:igfitidea点击:

How to return many Promises in a loop and wait for them all to do other stuff

javascriptpromiseecmascript-6es6-promise

提问by Ganbin

I have a loop which calls a method that does stuff asynchronously. This loop can call the method many times. After this loop, I have another loop that needs to be executed only when all the asynchronous stuff is done. So this illustrates what I want:

我有一个循环,它调用一个异步执行操作的方法。这个循环可以多次调用该方法。在这个循环之后,我有另一个循环,只有在所有异步工作都完成后才需要执行它。所以这说明了我想要的:

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

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

I'm not very familiar with promises, so could anyone help me to achieve this?

我对承诺不是很熟悉,所以有人可以帮助我实现这一目标吗?

This is how my doSomeAsyncStuff()behaves:

这是我的doSomeAsyncStuff()行为方式:

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

Maybe I have to do something like this:

也许我必须做这样的事情:

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

But I'm not sure of the syntax.

但我不确定语法。

回答by T.J. Crowder

You can use Promise.all(spec, MDN) for that: It accepts a bunch of individual promises and gives you back a single promise that is resolved when all of the ones you gave it are resolved, or rejected when any of them is rejected.

你可以使用Promise.all( spec, MDN):它接受一堆单独的承诺,并给你一个单一的承诺,当你给它的所有承诺都得到解决时,这个承诺得到解决,或者当其中任何一个被拒绝时被拒绝。

So if you make doSomeAsyncStuffreturn a promise, then:

所以如果你让doSomeAsyncStuffreturn 成为一个承诺,那么:

var promises = [];

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

Promise.all(promises)
    .then(() => {
        for(i=0;i<5;i+){
            doSomeStuffOnlyWhenTheAsyncStuffIsFinish();    
        }
    })
    .catch((e) => {
        // handle errors here
    });

Axel Rauschmayer has a good article on promises here.

阿克塞尔Rauschmayer先生对诺言的好文章在这里

Here's an example - live copy on Babel's REPL:

这是一个例子 - Babel 的 REPL 上的实时副本

 function doSomethingAsync(value) {
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log("Resolving " + value);
          resolve(value);
        }, Math.floor(Math.random() * 1000));
      });
    }
    
    function test() {
      let i;
      let promises = [];
      
      for (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();



(对此并不介意.catch.catch,但您确实想要.catch.catch现实世界中的那些,如前所示。)

Sample output (because of the Math.random, what finishes first may vary):

示例输出(由于 ,Math.random首先完成的内容可能会有所不同):

Resolving 3
Resolving 2
Resolving 1
Resolving 4
Resolving 0
All done [0,1,2,3,4]

回答by 2Toad

A reusable function works nicely for this pattern:

可重用函数非常适合这种模式:

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

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

  return Promise.all(promises);
}

OP example:

操作示例:

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


A related pattern, is iterating over an array and performing an async operation on each item:

一个相关的模式是迭代数组并对每个项目执行异步操作:

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

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

  return Promise.all(promises);
}

Example:

例子:

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

回答by JoeTidee

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