【问题标题】:javascript how use async await inside of a cycle in paralleljavascript如何在循环中并行使用异步等待
【发布时间】:2020-02-28 03:54:59
【问题描述】:

我在 express js 和 mongoose 中有下一个示例。学生和省之间存在关系:

app.get('/example', async (req, res) => {
const provinces = await Province.find();
let studentsByProvince = [];
for (let prov of provinces) {
    const st = await Student.count({ province: prov });
    studentsByProvince.push({ province: prov.province, totalStudents: st });
}
res.json(studentsByProvince);});

这不是有效的,因为在循环内搜索是按顺序执行的。我是这样解决的:

app.get('/example2', async (req, res) => {
const provinces = await Province.find();
let studentsByProvince = [];
let studentsByProvincePromises = [];
for (let prov of provinces) {
    const studentPromise = Student.count({ province: prov });
    studentsByProvincePromises.push(studentPromise);
}
const studentsByProvinceResult = await Promise.all(studentsByProvincePromises);

for (let [index, prov] of provinces.entries()) {
    studentsByProvince.push({ province: prov.province, totalStudents: studentsByProvinceResult[index] });
}
res.json(studentsByProvince);});

我已经解决了并行执行它的问题,但是我必须经历两次循环,因为查询返回的是一个承诺而不是结果。有 async await 某种方式来解决这个例子,类似于第一种方式,但是是并行的。

【问题讨论】:

  • 经历两次有什么问题?开销将非常低。你的意思是concurrently 吗?我在这里看不到任何并行性。 Promise 通过分时 afaik 执行。
  • “圈内”是什么意思?
  • @Pointy 我认为他的意思是“循环”。至少这是我从帖子中了解到的

标签: javascript node.js promise async-await


【解决方案1】:

您可以在第一个循环中将回调附加到 Promise:

app.get('/example2', async (req, res) => {
    const provinces = await Province.find();
    let studentsByProvincePromises = [];
    for (let prov of provinces) {
        const studentPromise = Student.count({ province: prov })
            .then(st => ({ province: prov.province, totalStudents: st });
        studentsByProvincePromises.push(studentPromise);
    }
    const studentsByProvince = await Promise.all(studentsByProvincePromises);

    res.json(studentsByProvince);
});

使用Array.prototype.map 会让内容看起来更简洁:

app.get('/example2', async (req, res) => {
    const provinces = await Province.find();

    const studentsByProvince = await Promise.all(
        provinces.map(prov => {
            return (Student.count({ province: prov })
                .then(totalStudents => ({ province: prov.province, totalStudents })
            )
        })
    );

    res.json(studentsByProvince);
});

【讨论】:

    【解决方案2】:

    我认为您可以以不同的方式实现这一点,甚至可以保存数据库查询。 既然您无论如何都想要所有省份(您也可以通过编程方式向管道添加过滤器),为什么不进行聚合?

    Student.aggregate([
      {
        $group:{
          _id: "$province", // this is the property we are grouping by 
          count: { $sum: 1 }
        }   
      }
    ])
    

    这将返回具有以下结构的对象数组:

    [
      {
        "_id" : "provinceName",
        "count" : 6
      },
      ....
    ]
    

    【讨论】:

    • Aldirrix 谢谢,但这个例子只是为了说明问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 2018-09-25
    • 1970-01-01
    • 2016-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多