在map函数中等待异步函数完成

4
考虑以下简单代码:

考虑以下简单的代码:

await Promise.all(arrayOfObjects.map(async (obj) => {
    return await someAsyncFunctionOnObj(obj);
}));

我的问题是,当执行arrayOfObjectssomeAsyncFunctionOnObj时,占用了过多的内存,因为循环不等待执行完成,而是对每个对象调用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
@dfsq 是的,我只是在展示基本概念。 - vrachlin
当你更想要链式调用时,为什么还要使用Promise.all呢? - Rob
@Robert,那正是我的问题,最好的链接方式是什么。 - vrachlin
你可能想要看看这里的示例,只需在第一个代码示例中将RSVP替换为Promise即可。它也很好地解释了这个问题。 - tocallaghan
3个回答

3

解决方案

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 的数组中,在迭代完所有项后返回该数组。
可以通过运行示例时查看瀑布图来确定函数的准确行为。您可以看到每个网络调用仅在前一个调用完成后才进行。

queueAsyncFns waterfall graph


谢谢您的解释,这更好地回答了我的问题! - vrachlin

1
如果你想在执行下一个对象(obj2, obj3, ...)之前等待一些异步函数在obj1上完成,我认为你需要链接你的Promise:

var promises = arrayOfObjects.map(obj => someAsyncFunctionOnObj(obj));
await promises.reduce((m, o) => m.then(() => o), Promise.resolve());


你能解释一下第二行吗? - vrachlin
它将var promises中的所有承诺等待它们,一个接一个地使用数组reduce(数组reduce使用m作为前一个承诺的内存,因此我们可以在m上执行.then并返回下一个承诺o,o成为新值m等等) - Faly

0
(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);
})();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接