如何遍历 node.js 中的一系列承诺?

Posted

技术标签:

【中文标题】如何遍历 node.js 中的一系列承诺?【英文标题】:How to iterate through an array of promises in node.js? 【发布时间】:2017-06-18 09:38:58 【问题描述】:

javascript 中,我有一个非平面的 Promises 数组:

const array = [
  [ promise11, promise12.. promise1n ],
  [ promise21, promise22.. promise2n ],
  [ promise31, promise32.. promise3n ],
  ...  
  [ promisek1, promisek2.. promisekn ]
];

如何以这种方式遍历数组,下一个 Promise 数组只有在前一个 Promise 数组解析后才开始解析?例如,我希望脚本等到 [ promise11, promise12.. promise1n ] 承诺并行解决,然后再调用下一个承诺数组。

我正在寻找一个通用解决方案,因为我的应用程序无法提前知道它必须进行多少次调用(它是一个网络抓取工具)。

【问题讨论】:

【参考方案1】:

可以使用Array#reduce 模式的变体:

array.reduce(
    (p, subArray) => p.then(() => Promise.all(subArray)),
    Promise.resolve()
);

这建立了一个承诺链,其中链中的每个条目都是来自Promise.all 的承诺的结果,用于数组中的子数组。

...但是:

...只有在前一个 promise 数组解析后,下一个 promise 数组才会开始解析?

这不是承诺的工作方式。一旦你有了承诺,它承诺的行动就已经在进行中。你不会“启动”它。

所以而不是,您希望将array 设为启动相关进程并return 承诺的函数数组,这略有不同:

function get(label) 
  console.log(label + "- starting");
  return new Promise(resolve => 
    setTimeout(() => 
      console.log(label + "- resolving");
      resolve(label);
    , Math.random() * 500);
  );

const array = [
  [ get.bind(null, "1a"), get.bind(null, "1b"), get.bind(null, "1c") ],
  [ get.bind(null, "2a"), get.bind(null, "2b") ],
  [ get.bind(null, "3a"), get.bind(null, "3b"), get.bind(null, "3c"), get.bind(null, "3d") ]
];

array.reduce(
  (p, subArray) => p.then(() => Promise.all(subArray.map(f => f()))),
  Promise.resolve()
).then(() => 
  console.log("All done");
);
.as-console-wrapper 
  max-height: 100% !important;

注意数组现在是一个函数数组,当调用它时“启动”进程,然后返回一个承诺。我们的Array#reduce 循环仅稍作修改:我们使用Array#map 调用此子数组的函数并获取它们的promise 数组,这就是我们输入Promise.all 的内容。因此,调用给定子数组的所有函数以开始该子数组的工作,然后我们等待它们全部完成,然后再继续下一个子数组并让它开始工作。

【讨论】:

您发布的第二个解决方案效果很好,但我仍然需要了解如何。无论如何,非常感谢! @simonas88:如果有什么我可以进一步解释的,请不要犹豫。 (p, subArray) => p.then(() => Promise.all(subArray.map(f => f()))) 这个reducer 似乎是解决方案的关键。我是否正确假设,当 Promise.all() 解决其参数中的所有承诺时 p.then() 返回(因此完成单个子数组)? @simonas88: then 立即返回。 什么它返回的是Promise.all返回的promise,稍后在map操作中创建的所有promise都结算后结算。 reduce 构建了这些“所有”承诺的链,每个承诺在调用其 then 回调并开始下一批之前等待它之前的一个解决。 好的,所以,reducer 很快就完成了,并返回了一连串未实现的承诺?而且由于在外部“链”中的每个链接都包含一个 Promise.all() 我得到了我所追求的顺序/并行行为?

以上是关于如何遍历 node.js 中的一系列承诺?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 node.js 中的特定持续时间后强制解决承诺? [复制]

Node.js 核心中的承诺 [重复]

如何在 node.js 中解决可变数量的承诺

Node.js承诺中的readline

如何让我的 Node.js MySQL 连接作为承诺工作?

如何在 Node js 中承诺一个 mysql 池连接?