一系列 Promise 是如何与 reduce 一起工作的?
Posted
技术标签:
【中文标题】一系列 Promise 是如何与 reduce 一起工作的?【英文标题】:How does an array of promises work exactly with reduce? 【发布时间】:2019-04-16 05:12:36 【问题描述】:我正在阅读这篇文章HERE,它讲述了如何将reduce 与promise 一起使用,最后显示了以下sn-p:
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
);
所以在不改变太多代码的情况下,我做了以下演示:
const tasks = [ fetch('https://jsonplaceholder.typicode.com/todos/1') ,
fetch('https://jsonplaceholder.typicode.com/todos/2') ,
fetch('https://jsonplaceholder.typicode.com/todos/3') ];
tasks.reduce((promiseChain, currentTask) =>
console.log(promiseChain);
return promiseChain.then(chainResults =>
return currentTask.then(currentResult =>
[ ...chainResults, currentResult ]
)
);
, Promise.resolve([])).then(arrayOfResults =>
// Do something with all results
console.log(arrayOfResults);
);
但我还是不明白,因为 reduce 只是一个简单的 forEach 循环,而在 reduce 内部,我们依赖于返回的承诺,那么 reduce 函数不会循环遍历数组中的所有元素的保证是什么(在这种情况下是一系列承诺),没有 then() 触发?
【问题讨论】:
它的承诺一直向下,它只是循环通过reduce元素并且代码的结构使得您正在创建一个.then
操作的大链。我可以看到这样做的原因(您需要中间值才能进行下一次调用),但在您的示例中,Promise.all(tasks).then()
可能是更好的解决方案。
Promise 数组根本不适用于reduce
,您只需使用Promise.all
。但是,您正在谈论一系列任务(返回承诺的函数)。
...确实,您在此处发布的代码不能按顺序运行,它会立即执行三个 fetch
请求。
"reduce 只是一个 forEach 循环" - 最好反过来看:forEach
只是一个 reduce
循环,但忽略返回值。
你可能想看看***.com/a/30823708/1048572
【参考方案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 函数返回已解决的承诺,您可以将另一个函数链接到它的末尾以处理完成的链。
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)
【讨论】:
请给我一些时间来看看你的回答并接受。感谢您的帮助 +1。 精彩的解释!非常感谢,绝对精彩!令人兴奋的......太棒了!以上是关于一系列 Promise 是如何与 reduce 一起工作的?的主要内容,如果未能解决你的问题,请参考以下文章