如何在循环中返回许多Promise并等待它们全部做其他事情

Gan*_*bin 49 javascript promise ecmascript-6 es6-promise

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

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

for (i = 0; i < 5; i++) {
    doSomeStuffOnlyWhenTheAsyncStuffIsFinish();    
}
Run Code Online (Sandbox Code Playgroud)

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

这是我的doSomeAsyncStuff()表现:

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

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

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

但我不确定语法.

T.J*_*der 113

您可以使用Promise.all(规范,MDN):它接受一堆单独的承诺,并为您提供一个单一的承诺,当您提供的所有承诺得到解决时被解决,或者当它们中的任何一个被拒绝时被拒绝.

因此,如果您doSomeAsyncStuff返回承诺,那么:

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
    });
Run Code Online (Sandbox Code Playgroud)

Axel Rauschmayer在这里有一篇关于承诺的好文章.

这是一个例子 - 关于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();
Run Code Online (Sandbox Code Playgroud)

(对此并没有打扰.catch,但你确实想要.catch你现实世界的那些,如前所示.)

样本输出(因为,Math.random首先完成的可能会有所不同):

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

  • 哇,非常感谢,现在我对promises有了更多的了解.我读了很多关于promises的内容,但是在我们需要在实际代码中使用它们之前,我们并不真正理解所有的机制.现在我做得更好,我可以开始写很酷的东西了,谢谢你. (11认同)

2To*_*oad 9

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

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

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

  return Promise.all(promises);
}
Run Code Online (Sandbox Code Playgroud)

操作示例:

awaitAll(5, doSomeAsyncStuff)
  .then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results))
  .catch(e => console.error(e));
Run Code Online (Sandbox Code Playgroud)

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

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

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

  return Promise.all(promises);
}
Run Code Online (Sandbox Code Playgroud)

例子:

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));
Run Code Online (Sandbox Code Playgroud)

  • 这确实使代码更容易理解和更清晰。我不认为当前的示例(显然是根据OP的代码改编的)能够做到这一点。这是一个巧妙的技巧,谢谢! (2认同)