我正在尝试将async
/ await
与reduce
方法一起使用。但是以某种方式,只有循环的第一次迭代有效。一旦完成第一次await
迭代,papers对象将跳过reduce
。是否可以使用reduce
创建对象,同时从承诺中收集内容,同时还要等待整个过程?
缩小功能:
const papers = await page.concepts.reduce(async (acc, cur) => {
acc[cur.paperID] = await getPageData(`papers/${ cur.paperID }`, 'md')
return acc
}, {})
注意:getPageData
返回一个承诺。
答案 0 :(得分:2)
您可以创建一个承诺数组,然后使用Promise.all
来解决它们。如果任何请求失败,Promise.all
将停止处理其余请求。
const papersPromises = page.concepts.map(cur =>
getPageData(`papers/${ cur.paperID }`, 'md')
)
const result = await Promise.all(papersPromises)
// result will be an array with the results
答案 1 :(得分:1)
这是将数组折叠到对象中的一种方法,但是自然地,它不会处理异步函数并减少自身。另外,reduce不会返回Promise来等待
您可以使用Promise.all和Object.fromEntries
解决您的情况// map concepts to promises which will resolve to page data for each concept
// and await for them all at once (will run in parallel)
const pageResponses = await Promise.all(page.concepts.map(concept => getPageData(`papers/${concept.paperID}`, 'md')))
// construct object where keys are concept.paperIDs and values are pageDatas
const papers = Object.fromEntries(
page.concepts
.map((concept, i) => ([concept.paperID, pageResponses[i]]))
)
如果您的运行时不支持Object.fromEntries(并且您没有使用polyfill),则可以执行最后一部分
const papers = page.concepts.reduce((acc, concept, index) => acc[concept.paperID] = pageResponses[index], {})
答案 2 :(得分:1)
由于异步函数返回了一个Promise,因此您必须期望累加器是一个Promise。因此,您将执行以下操作:
console.log("Program starting at", Date());
function delayedResolver(a, ms) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log("resolving at", Date());
resolve(a);
}, ms);
});
}
arr = [1, 3, 5];
r = arr.reduce(async function(a, b) {
return await delayedResolver(a, 3000).then(v => v + b);
}, Promise.resolve(0));
console.log(r);
r.then(v => console.log("final value", v, "at", Date()));
您必须将累加器视为一个承诺,并每次都返回一个新的承诺。
请注意,异步函数返回一个诺言,而reduce
立即将异步函数应用于下一对(accumulator, entry)
,因此异步函数返回的所有这些诺言几乎都是立即创建的,因此为什么承诺会在3秒后全部解决,而不是一一解决。