【问题标题】:Javascript async/await execution order problem in for...of, for await...of and Promise.allfor...of、forawait...of 和 Promise.all 中的 Javascript async/await 执行顺序问题
【发布时间】:2021-01-27 22:48:59
【问题描述】:

对于数组(产品)中的每个对象(产品),我从猫鼬数据库中获取价格。该值 (prodDB.price) 与循环前初始化为 0 的“金额”变量相加。

我尝试了其他问题中解释的 3 个解决方案,其中:

  • 为的
  • 等待的
  • Promise.all

---对于---

 let amount = 0;
     
 for (const product of products) {
     await Product.findById(product._id).exec((err, prodDB)=> {
         amount += product.count * prodDB.price;
         console.log("Current amount", amount);
     });
 };
 console.log("Amount total", amount);

--- 等待 ---

 let amount = 0;
     
 for await (const product of products) {
     Product.findById(product._id).exec((err, prodDB)=> {
         amount += product.count * prodDB.price;
         console.log("Current amount", amount);
     });
 };
 console.log("Amount total", amount);

--- Promise.all ---

let amount = 0;

await Promise.all(products.map(async (product)=> {
    await Product.findById(product._id).exec((err, prodDB)=> {
    amount += product.count * prodDB.price;
    console.log("Current amount", amount);
    });
}));

 console.log("Amount total", amount);

任何以前版本的代码的结果总是相同的,而且是出乎意料的,尤其是 console.log 发生的顺序:

Amount total 0
Current amount 10.29
Current amount 17.15
Current amount 18.29
Current amount 19.45
Current amount 43.2

你能帮忙吗? 非常感谢!

【问题讨论】:

    标签: javascript loops promise async-await


    【解决方案1】:

    问题是您混合了“回调”模式和“等待”模式。要么await操作,要么给它一个回调,否则它会变得混乱。

    for (const product of products) {
        let prodDB = await Product.findById(product._id).lean().exec(); // add lean() to get only JSON data, lighter and faster
        amount += product.count * prodDB.price;
        console.log("Current amount", amount);
    };
    

    但是,这非常昂贵,因为如果您有 10 种产品,您将调用您的数据库 10 次。最好只调用一次,一次性获取所有 _id。

    let allIds = products.map(p => p._id),
        prodDBs = await Product.find({
            _id: {
                $in: allIds
            }
        })
        .lean()
        .exec()
    
    const amount = prodDBs.reduce((a,b) => a.price + b.price, 0)
    

    【讨论】:

      【解决方案2】:

      我会使用Promise.all,这样您就可以并行运行所有数据库请求并等待所有请求完成,而不是串联运行所有请求。我认为唯一的问题是.exec() 没有返回Promise,只需使用返回Promise 的findById(),试试这个代码:

      let amount = 0;
      
      await Promise.all(products.map(async (product)=> {
        const prodDB = await Product.findById(product._id)
        amount += product.count * prodDB.price
      }));
      

      【讨论】:

      • 仍然进行 10 次数据库调用,而不是 1 次:/
      猜你喜欢
      • 1970-01-01
      • 2018-12-15
      • 2022-08-14
      • 2021-08-15
      • 2018-06-27
      • 2020-11-05
      • 2020-04-13
      • 2022-11-23
      • 2021-09-30
      相关资源
      最近更新 更多