我正在通过以下方式减少嵌套承诺数组:
const promises = items.map((item, index) => {
console.log(index);
return doAsyncThing(item).then(() => {
console.log(index);
});
});
return promises.reduce((acc, p) => acc.then(() => p), Promise.resolve());
我希望console.log
条目打印出来
0 0 1 1 2 2
但他们正在打印
0 1 2 2 1 0
如何重构我的代码,以便在操作1之前完成整个操作0,这在选项2之前完成,等等......?
答案 0 :(得分:2)
您的实现的问题是所有的promises都是同时创建的,这将导致他们在那时将异步操作放在事件队列中。在您的情况下,这发生在map
函数中。让我们来看看。
// your current code
const promises = items.map((item, index) => {
console.log(index); // this happens immediately and waits for nothing, which is why you see `0 1 2` in the console
return doAsyncThing(item) // right here the async action is created
.then(() => { // this will run as soon as the async action is finished
console.log(index);
});
});
在此步骤之后,promises
已经是一个承诺数组,所有这些承诺已经排队等待异步操作,而不是等待其他任何操作完成。
你对reduce有正确的想法,但是当你的reduce运行时,所有的promise都已经创建,并且将以它们完成的任何顺序运行。如果要强制执行订单,则需要使用reduce来创建最初的承诺:
const promises = items.reduce((acc, item, index) => {
console.log(index) // still runs immediately
return acc
.then(() => doAsyncThing(item)) // creates the promise after acc finishes
.then(() => console.log(index)); // runs after doAsyncThing finishes
}, Promise.resolve());
这将在您的控制台中生成输出0 1 2 0 1 2
,但在操作0完成之前,操作1仍将不会运行,并且在操作1完成之前不会运行操作2。我希望这有帮助!