繁体   English   中英

嵌套异步等待未按预期工作

[英]Nested async await not working as expected

我正在尝试在我现有的代码中为一些数据添加一个表,为此我已经设置了类似于 exceljs 文档中提到的所有内容。 这是我试图获取我需要的数据以获取表格的条件的代码片段。 当我在 forEach 中打印 modRows 时,它会显示数据,但是当我在循环外打印它时,它变得空白。 有什么办法或其他解决方法吗? 异步中是否可以有异步?

const generateCatReports = async (mode = 'monthly', months = 1, toDate = false) => {
  if (!['monthly', 'weekly'].includes(mode)) {
    throw new Error(InvalidParamsError);
  }
 const sortedTRIds = obtainSortedCentreIds(studiesTRMap, centreNameIDMap);
  const modRows = [];
  sortedTRIds.forEach(async (trId) => {
    console.log("trid",trId);
    const statsParams = {
      catId: trId,
      createdAt,
    };
    const statsPipeline = studiesStatsPipeline(statsParams, capitalize(mode));
    const statsInfo = await StudyModel.aggregate(statsPipeline).allowDiskUse(true).exec();
    Object.entries(statsInfo[0]).slice(1).forEach(([key, val]) => {
      modRows.push([key, val]);
    });
    console.log("inside sortedTr loop>>>>>" ,modRows);
  });
  console.log("outside sortedTr loop>>>>>>>>",modRows);

}

结果:

trId 1cf1eb1324322bbebe
inside sortedTr loop>>>>>>>>>>
['TOTAL', 10]
['white', 5]
['black', 5]

trId 1cf1eb1324322bbebe
inside sortedTr loop>>>>>>>>>>
['TOTAL', 10]
['white', 5]
['black', 5]

trId 21e1eb21322bbebe
inside sortedTr loop>>>>>>>>>>
['TOTAL', 8]
['white', 6]
['black', 2]

outside sortedTr loop>>>>>>>>>>
[]

async/await不能在forEach循环中forEach 您可以在简单的 for 循环或一段时间内使用它,执行...

例如:

export async function asyncForEach(array, callback) {
  for (let index = 0; index < array.length; index++) {
    await callback(array[index], index, array);
  }
}

每当您看到像.forEach(async (trId) => {这样的异步回调时,出现问题的可能性非常高。

您遇到的问题是async函数实际上是承诺,因此它们不会阻塞主线程。 这意味着您的回调函数会在作业队列中排队,并将在将来执行。

它的简化是这样的:

let arr = []
setTimeout(() => {
   arr.push("hy")
})
console.log(arr)

arr 将是空的,

但是,您可以使用for ... of循环

const generateCatReports = async (
  mode = "monthly",
  months = 1,
  toDate = false
) => {
  if (!["monthly", "weekly"].includes(mode)) {
    throw new Error(InvalidParamsError);
  }
  const sortedTRIds = obtainSortedCentreIds(studiesTRMap, centreNameIDMap);
  const modRows = [];
  for (const trId of sortedTRIds) {
    const statsParams = {
      catId: trId,
      createdAt
    };
    const statsPipeline = studiesStatsPipeline(statsParams, capitalize(mode));
    const statsInfo = await StudyModel.aggregate(statsPipeline)
      .allowDiskUse(true)
      .exec();
    Object.entries(statsInfo[0])
      .slice(1)
      .forEach(([key, val]) => {
        modRows.push([key, val]);
      });
    console.log("inside sortedTr loop>>>>>", modRows);
  }
  console.log("outside sortedTr loop>>>>>>>>", modRows);
};

在这里,您没有将排队的回调。

更好的解决方案是使用Promise.all()

const generateCatReports = async (
  mode = "monthly",
  months = 1,
  toDate = false
) => {
  if (!["monthly", "weekly"].includes(mode)) {
    throw new Error(InvalidParamsError);
  }
  const sortedTRIds = obtainSortedCentreIds(studiesTRMap, centreNameIDMap);
  const modRows = await Promise.all(
    sortedTRIds.flatMap(async (trId) => {
      const statsParams = {
        catId: trId,
        createdAt
      };
      const statsPipeline = studiesStatsPipeline(statsParams, capitalize(mode));
      const statsInfo = await StudyModel.aggregate(statsPipeline)
        .allowDiskUse(true)
        .exec();
      return Object.entries(statsInfo[0]).slice(1);
    })
  );

  console.log(modRows);
};

这就是为什么你不应该在 forEach 循环中使用 async/await,

forEach 循环接受回调,即使您将异步函数作为回调传递,也不会等待。 您的异步回调将等待其中的任何承诺,但 forEach 循环将继续为数组中的所有元素执行回调函数。

而是使用for...in循环,正如预期的那样,在for...in循环中的 await 将停止循环执行,并且仅在您完成等待承诺时继续迭代。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM