如何返回许多承诺,并在做其他事情之前等待它们

我有一个循环,它调用一个异步执行操作的方法。此循环可以多次调用该方法。在此循环之后,我还有另一个循环,只有在完成所有异步操作时才需要执行。

所以这说明了我想要什么:

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

但我不确定语法。


答案 1

你可以使用(规范MDN)来实现这一点:它接受一堆单独的承诺,并给你一个承诺,当你给它的所有承诺都得到解决时,这个承诺就会得到解决,或者当其中任何一个被拒绝时,它就会被拒绝。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
        });

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

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

答案 2

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

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

一个相关的模式是循环访问数组并对每个项目执行异步操作:

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