提问人:Ganbin 提问时间:7/15/2015 最后编辑:HenkeGanbin 更新时间:5/21/2022 访问量:152972
如何返回许多 Promise 并在做其他事情之前等待它们
How to return many Promises and wait for them all before doing other stuff
问:
我有一个循环,它调用一个异步执行操作的方法。此循环可以多次调用该方法。在这个循环之后,我还有另一个循环,只有在所有异步操作完成后才需要执行。
所以这说明了我想要什么:
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);
});
});
}
但我不确定语法。
答:
260赞
T.J. Crowder
7/15/2015
#1
你可以使用 (spec, MDN):它接受一堆单独的 promise,并给你一个 promise ,当你给它的所有 promise 都得到解决时,这个 promise 就会得到解决,或者当其中任何一个被拒绝时,这个 promise 就会被拒绝。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:新玩具》的第 8 章中详细介绍了 propromises,如果您有兴趣,可以在我的个人资料中链接。
下面是一个示例:
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]
评论
0赞
Ganbin
7/15/2015
好的,谢谢,我现在尝试这个,我会在几分钟内提供反馈。
14赞
Ganbin
7/15/2015
哇,非常感谢,现在我更了解了这些承诺。我读了很多关于承诺的文章,但是在我们需要在实际代码中使用它们之前,我们并不真正理解所有的机制。现在我变得更好了,我可以开始写很酷的东西了,多亏了你。
1赞
OK sure
1/12/2018
此外,如果您出于任何原因(例如模拟进度)想要按顺序完成这些任务,则可以更改为Math.floor(Math.random() * 1000)
(i * 1000)
0赞
noobCoder
3/7/2019
如果返回一个承诺,如何等待它与循环中的其他人一起完成?doSomethingAsync(i)
1赞
T.J. Crowder
7/24/2019
@user1063287 - 如果代码位于允许的上下文中,则可以执行此操作。目前,您唯一可以使用的地方是函数内部。(在某些时候,您还可以在模块的顶层使用它。await
await
async
14赞
2Toad
10/24/2019
#2
可重用的函数适用于此模式:
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));
评论
2赞
Shaun Vermaak
6/8/2020
这确实使代码更易于理解和更简洁。我不认为当前的例子(显然适应了 OP 的代码)做到了这一点。这是一个巧妙的技巧,谢谢!
3赞
JoeTidee
4/3/2020
#3
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)),
]);
3赞
842Mono
6/5/2020
#4
这是我为自己编写的代码,以便理解此处所述的答案。我在 for 循环中有猫鼬查询,所以我把 to 放在这里来代替它。希望它对任何人有所帮助。您可以在 node 或许多 Javascript 运行时中的任何一个运行此脚本。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!");
}
)
4赞
Sourav Purkait
7/4/2020
#5
/*** 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
0赞
natanavra
7/15/2021
#6
如果您想多次做同样的事情,这里有一个优雅的解决方案:
await Promise.all(new Array(10).fill(0).map(() => asyncFn()));
这将创建一个包含 10 个项目的数组,用零填充它,然后将其映射到一个 promise 数组。
评论
s
Promise