等待异步功能完成内部地图
Posted
技术标签:
【中文标题】等待异步功能完成内部地图【英文标题】:Waiting for async function to complete inside map 【发布时间】:2018-03-30 05:46:59 【问题描述】:考虑下面的简单代码代码:
await Promise.all(arrayOfObjects.map(async (obj) =>
return await someAsyncFunctionOnObj(obj);
));
我的问题是,arrayOfObjects 和 someAsyncFunctionOnObj 在执行时占用了太多内存,因为循环不会等待执行完成,而是调用 someAsyncFunctionOnObj (obj),在每一个上,并等待 全部解决,不需要按顺序,这会导致 OOM 崩溃。 我试过使用递归异步函数,它确实解决了顺序问题,但仍然导致 OOM 崩溃。
我要实现的流程是同步循环,意思是
await someAsyncFunctionOnObj(obj1); // wait for it to finish
await someAsyncFunctionOnObj(obj2); // wait for it to finish
...
对如何正确实施有什么建议吗?
【问题讨论】:
首先应该是return await someAsyncFunctionOnObj(obj);
但是如果你使用Promise.all
,你真的不需要async/await。或者只是await Promise.all(arrayOfObjects.map(someAsyncFunctionOnObj));
@dfsq 是的,我只是在展示基本概念。
当你想要链接 Promise.all 时,为什么还要使用它们?
@Robert 这正是我的问题,链接它们的最佳方式是什么。
您可能想要来自here 的示例,只需将第一个代码示例中的 RSVP 替换为 Promise 即可。它也很好地解释了它
【参考方案1】:
解决方案
async function queueAsyncFns(fns)
const values = [];
await fns.reduce((previous, current, index, array) =>
const thenable = index === 1 ? previous() : previous;
return thenable.then(value =>
values.push(value);
return index === array.length - 1 ? current().then(value => values.push(value)) : current();
);
);
return values;
示例
const anArray = [1, 2, 3];
const doSomething = async (id) => await fetch(`https://jsonplaceholder.typicode.com/users/$id`).then(res => res.json());
queueAsyncFns(anArray.map((val) => () => doSomething(val))).then((val) => console.log(val));
上述功能应该可以解决您的问题。以下是它的作用的简要概述:
queueAsyncFns
接受一个函数数组,该数组返回调用异步函数的结果。通过调用每个函数并将 Promise 返回到 reducer 的下一次调用来减少该数组。在每次迭代中,异步调用的值都会累积到一个名为 values
的数组中,该数组会在所有项都被迭代后返回。
在运行示例时,可以通过查看瀑布图直观地确定函数的准确行为。您可以看到每个网络调用都是在前一个调用完成后进行的。
【讨论】:
感谢您的解释,这更好地回答了我的问题!【参考方案2】:如果你想等待 someAsyncFunctionOnObj(obj1) 完成,然后再做同样的事情,但使用下一个对象(obj2,obj3,...),我认为你必须链接你的承诺:
var promises = arrayOfObjects.map(obj => someAsyncFunctionOnObj(obj));
await promises.reduce((m, o) => m.then(() => o), Promise.resolve());
【讨论】:
你能解释一下第二行吗? 它获取 var Promise 中的所有 Promise 并通过使用数组 reduce 一个接一个地等待它们(array reduce 使用 m 作为前一个 Promise 的内存,所以我们可以做 .then on m 并返回下一个 promise o,o 成为 m 的新值,依此类推)【参考方案3】:(async function()
async function executeSequentially()
const tasks = [1,2]
const total = []
for (const fn of tasks)
const res = await fetch(endpoint);
const res2 = await res.json();
console.log(res2[0]);
total.push(...res2);
return total;
const res = await executeSequentially();
console.log(res);
)();
【讨论】:
以上是关于等待异步功能完成内部地图的主要内容,如果未能解决你的问题,请参考以下文章
在映射下一项之前,异步等待映射不等待异步函数在映射函数内部完成