【问题标题】:why javascript not wait for and of forEach and execute next line [duplicate]为什么javascript不等待forEach并执行下一行[重复]
【发布时间】:2018-08-16 18:54:02
【问题描述】:

当我在 nodejs 中创建我的 api 并尝试将 mongoose 返回计数推送到新创建的数组时,它不会等待 forEach 并执行 json.res() 并给出空响应。当我使用 setTimeout() 那么它给出了正确的结果。

let newcategories = [];
let service = 0;
const categories = await Category.find({}, '_id name');
categories.forEach(async (category) => {

service = await Service.count({category: category});

newcategories.push({ count:service });
console.log('newcategories is -- ', newcategories);

});  /* while executing this forEach it's not wait and execute res.json..*/


console.log('result --- ',result);
console.log('out newcategories is -- ', newcategories);
res.json({status: 200, data: newcategories});

【问题讨论】:

  • 好吧,你不能等待forEach,但是回调函数被标记为async(所以它会自动返回一个Promise)。所以forEach 在你所有的等待准备好之前就已经完成了。只需将forEach 更改为for let category of categories 并在for..of 块内等待
  • 是的,它工作正常............非常感谢:)
  • for (let category of categories) { service = await Service.count({category: category}); newcategories.push({ _id: category._id, name: category.name, count: service }); }
  • 你可以使用reduce来连续运行这个:categories.reduce(async (previous, category) => { await previous; service = await Service.count... }, null);

标签: javascript node.js angular reactjs es6-promise


【解决方案1】:

您需要使用 map 而不是 forEach 来收集 await 并等待它们完成。编辑:或者你可以使用for..of,它非常简洁(感谢其他人)!

const categories = ['a', 'b', 'c'];

function getNextCategory(oldCategory) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(String.fromCharCode(oldCategory.charCodeAt(0)+1));
    }, 1000);
  });
}

async function blah() {
  const categoryPromises = categories.map(getNextCategory);

  const nextCategories = await Promise.all(categoryPromises);

  console.log(nextCategories);
}

blah();

async function blah2() {
  const nextCategories = [];

  for (const category of categories) {
    nextCategories.push(await getNextCategory(category));
  };

  console.log(nextCategories);
}


blah2();

【讨论】:

  • 是的,在此之前我实际上并不知道为..of 工作,所以这很酷
【解决方案2】:

所以你遇到的问题是async 标记的函数将默认返回一个承诺,但Array.prototype.forEach 方法并不关心你的回调函数的结果类型,它只是执行一个动作。

在您的async 函数中,它会正确地await 您的回复并填写您的新类别,但类别上的forEach 循环将早已不复存在。

您可以选择将语句转换为 for .. of 循环,也可以使用 map 然后 await Promise.all( mapped )

for..of 循环是这样的

for (let category of categories) {
  service = await Service.count({category: category});

  newcategories.push({ count:service });
  console.log('newcategories is -- ', newcategories);
}

地图版本如下所示

await Promise.all( categories.map(async (category) => {
  service = await Service.count({category: category});

  newcategories.push({ count:service });
  console.log('newcategories is -- ', newcategories);
}));

第二个版本很简单,因为Promise.all 只会在所有承诺完成后才解决,并且地图将为每个类别返回一个可能未解决的承诺

【讨论】:

  • 非常感谢!我需要什么(for..of 循环)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 2019-07-25
  • 1970-01-01
  • 2018-05-10
  • 1970-01-01
  • 2023-03-11
相关资源
最近更新 更多