在映射下一项之前,异步等待映射不等待异步函数在映射函数内部完成

Posted

技术标签:

【中文标题】在映射下一项之前,异步等待映射不等待异步函数在映射函数内部完成【英文标题】:Async Await map not awaiting async function to complete inside map function before mapping next item 【发布时间】:2021-03-06 18:28:08 【问题描述】:

我有一个要映射的数组,在 map 函数中我正在调用一个异步函数,它正在执行一个异步请求,返回一个使用 request-promise 的承诺。

我期望数组的第一项被映射,执行请求,然后第二项重复相同的过程。但这不是在这种情况下发生的事情。

这是我的功能;

const fn = async() => 
  const array = [0, 1, 2];
  console.log('begin');
  await Promise.all(array.map(item => anAsyncFunction(item)));
  console.log('finished');
  return;

anAsyncFunction如下;

const anAsyncFunction = async item => 
  console.log(`looping $item`);
  const awaitingRequest = await functionWithPromise(item);
  console.log(`finished looping $item`);
  return awaitingRequest;

以及发出请求的functionWithPromise

const functionWithPromise = async (item) => 
  console.log(`performing request for $item`);
  return Promise.resolve(await request(`https://www.google.com/`).then(() => 
    console.log(`finished performing request for $item`);
    return item;
  ));

从我得到的控制台日志中;

begin
looping 0
performing request for 0
looping 1
performing request for 1
looping 2
performing request for 2
finished performing request for 0
finished looping 0
finished performing request for 1
finished looping 1
finished performing request for 2
finished looping 2
finished

但是,我想要的是

begin
looping 0
performing request for 0
finished performing request for 0
finished looping 0
looping 1
performing request for 1
finished performing request for 1
finished looping 1
looping 2
performing request for 2
finished performing request for 2
finished looping 2
finished

我通常会接受这种模式,但我似乎从请求调用中得到了一些无效的正文,因为我可能一次制作了太多。

有没有更好的方法来实现我想要实现的目标

【问题讨论】:

你不能等待之前的承诺在 .map 内完成......使用 for 循环,或结构良好的 reduce 循环 【参考方案1】:

.map() 不支持异步或承诺。它只是尽职尽责地获取您从其回调中返回的值并将其填充到结果数组中。即使在您的情况下这是一个承诺,它仍然会继续进行,而不是等待那个承诺。而且,在这方面您无法更改 .map() 行为。这就是它的工作方式。

改为使用for 循环,然后在循环内使用await 异步函数,这将暂停循环。


你的结构:

await Promise.all(array.map(item => anAsyncFunction(item)));

正在并行运行所有 anAsyncFunction() 调用,然后等待所有调用完成。


要按顺序运行它们,请使用for 循环和await 单独的函数调用:

const fn = async() => 
  const array = [0, 1, 2];
  console.log('begin');
  for (let item of array) 
      await anAsyncFunction(item);
  
  console.log('finished');
  return;

重要的是要知道没有任何数组迭代方法是异步感知的。这包括.map().filter().forEach() 等...因此,如果您想在循环内等待某些内容以对异步操作进行排序,请使用常规的for 循环,即async知道并将暂停循环。

【讨论】:

以上是关于在映射下一项之前,异步等待映射不等待异步函数在映射函数内部完成的主要内容,如果未能解决你的问题,请参考以下文章

如何等待此功能完成?

如何在 javascript 中同步异步映射函数

Event Loop

Nodejs 等到异步映射函数完成执行

在 python 中等待之前,不会在异步函数中调用 print 函数

NodeJS,如何强制异步 for 循环在传递到下一次迭代之前等待 HTTP 请求解决,这样我们就不会收到 EMFILE 错误?