减少嵌套承诺

时间:2017-11-14 19:41:18

标签: javascript arrays promise

我正在通过以下方式减少嵌套承诺数组:

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之前完成,等等......?

1 个答案:

答案 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。我希望这有帮助!