繁体   English   中英

使用 map 或 foreach 异步/等待

[英]Async/Await with map or foreach

我试图从我的数据库中检索一堆产品价格,并假设我可以通过它们映射或 foreach,并将价格 += 到一个变量上,如下所示:

// Get Total
exports.getTotal = (req,res) => {
  let productList = req.body;
  let total = 0;

  const results = productList.map(async (product) => {
      Product.findById(product._id)
          .select('price')
          .exec((err, foundProduct) => {
              if (err){
                  console.log(`Error: Product with id ${product._id} not found.`);
              } else {
                  console.log('Product price. ', foundProduct.price);
                  total += foundProduct;
              }
          })
  });

  Promise.all(results).then(data => console.log('Total is', total));

};

然而,总的console.log 总是返回0。我怀疑console.log 在映射和数据库查找承诺完成之前运行的问题。

任何指导表示赞赏。

您以错误的方式使用 exec Exec 会给您一个承诺。 你可以简化这个

// Get Total
exports.getTotal = (req, res) => {
  const productList = req.body;
  let total = 0;

  const results = productList.map(async product => {
    const foundProduct = await Product.findById(product._id).exec();
    total += foundProduct;
    return foundProduct;
  });

  Promise.all(results).then(data => console.log("Total is", total));
};

你忘了等待异步函数await Product.findById(product._id)

此外,通过使用数组减少,以功能方式编写可以消除此类任务的混乱

// Get Total
exports.getTotal = (req, res) => {
  const results = req.body.reduce(async (total, product) => {
    await Product.findById(product._id)
      .select('price')
      .exec((err, foundProduct) => {
        if (err){
          console.log(`Error: Product with id ${product._id} not found.`);
          return total
        } else {
          console.log('Product price. ', foundProduct.price);
          return total += foundProduct;
        }
      })
  }, 0);

  Promise.all(results).then(data => console.log('Total is', data));
};

Array 的map()foreach()和其他迭代方法不使用 promise。 因此,使回调async不会使内部迭代在对回调进行下一次迭代调用之前等待。 此外,您的地图将充满永远不会得到解决的承诺,因为您永远不会返回任何东西,这相当于拥有

Promises.all([new Promise(), new Promise(), new Promise()])

您可以更改代码以创建新承诺的正确映射,然后在获取所有内容后计算总数。 请注意,由于exec()本身返回一个承诺,您只需返回:

const results = productList.map(product=> {
  return Product.findById(product._id).select('price').exec();
});
Promise.all(results).then(values => {
  let total = values.reduce((a, b) => a + b);
  console.log(`Total: ${total}`)
});

您也可以在独立的async函数中使用 for 循环并使用await

async function getTotal(){
  let total = 0;
  for(let product of productList){
    let price = await Product.findById(product._id).select('price').exec();
    total+=price;
  }
  return total;
}

getTotal().then(total=>console.log(`Total: ${total}`));

暂无
暂无

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

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