一系列诺言如何与reduce完全配合?

时间:2018-11-13 11:16:45

标签: javascript es6-promise

我正在阅读这篇文章HERE,其中谈到了如何使用带有promise的reduce,最后显示了以下片段:

ZBProfileManager

因此,在不更改大部分代码的情况下,我进行了以下演示:

const tasks = getTaskArray();
return tasks.reduce((promiseChain, currentTask) => {
    return promiseChain.then(chainResults =>
        currentTask.then(currentResult =>
            [ ...chainResults, currentResult ]
        )
    );
}, Promise.resolve([])).then(arrayOfResults => {
    // Do something with all results
});

但是我还是不明白,因为简而言之,reduce只是一个forEach循环,而在reduce内部,我们依靠的是返回的Promise,那么reduce函数将不会遍历数组中的所有元素,这有什么保证呢? (在这种情况下,是一个promise数组),而没有then()触发?

1 个答案:

答案 0 :(得分:1)

好吧,请从阅读本文中获得更完整的答案。此策略适用于相互依赖但并不总是相同的异步任务。如果它们是固定结构,则可以这样做(根据示例):

return task1.then(result1 =>
    task2.then(result2 =>
        task3.then(result3 =>
            [ result1, result2, result3 ]
        )
    )
).then(arrayOfResults => {
    // Do something with all results
});

从做数据库工作的角度考虑这一点。

return dbOrm.task1.create()
  .then(newRecord =>
    // task 2 requires the id from the new record to operate
    dbOrm.task2.create({task1_id: newRecord.id})
      .then(result2 =>
        // some other async that relies on result2
        task3(result2).then(result3 =>
            [ result1, result2, result3 ]
        )
    )
).then(arrayOfResults => {
    // Do something with all results
});

这是一组固定的依赖关系,它们彼此依赖,因此您需要所有这些结果的结果才能继续。

您链接的示例旨在用于那种串行执行,但在具有非固定依赖项的情况下。 Reduce用于同步构造一个异步动作链,然后可以自行解决。由于reduce函数返回已解析的Promise,因此您可以在其末尾链接另一个函数以处理完整的链。

Reduce不仅是forEach循环,即使它们都使用迭代来移动数组。 Reduce还可以将前一次迭代的返回结果传递到下一次迭代。您正在将您的任务组“缩减”为一个已完成的任务; forEach不会更改其正在操作的数组(而Map,另一个迭代数组函数,从旧数组返回修改后的新数组)。

因此请使用示例代码:

const tasks = getTaskArray();
return tasks.reduce((promiseChain, currentTask) => {
    return promiseChain.then(chainResults =>
        currentTask.then(currentResult =>
            [ ...chainResults, currentResult ]
        )
    );
}, Promise.resolve([])).then(arrayOfResults => {
    // Do something with all results
});

如果进行2次迭代,您将得到类似的内容:

// 1
Promise.resolve([])
  .then(chainResults => task1().then(task1Result => ([ ...chainResults, task1Result])

// 2
Promise.resolve([])
  .then(chainResults => task1().then(task1Result => ([ ...chainResults, task1Result])
  .then(chainResults => task2().then(task2Result => ([ ...chainResults, task2Result])

// the then after the reduce
Promise.resolve([])
  .then(chainResults => task1().then(task1Result => ([ ...chainResults, task1Result])
  .then(chainResults => task2().then(task2Result => ([ ...chainResults, task2Result])
  .then(arrayOfResults => //do Something)
  .catch(//because you should handle errors)