javascript как использовать asyn c внутри цикла ожидания - PullRequest
0 голосов
/ 27 февраля 2020

У меня следующий пример в express js и пн goose. Существуют отношения между студентом и провинцией:

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);});

Я уже решил проблему его параллельного выполнения, однако мне приходится go проходить через цикл дважды, поскольку запрос возвращает обещание, а не результат. Существует асин c, ждите какой-нибудь способ решить этот пример, аналогичный первому, но параллельно.

Ответы [ 2 ]

0 голосов
/ 27 февраля 2020

Я думаю, что вы можете достичь этого по-другому и даже сохранить запрос к базе данных. Поскольку вам все равно нужны все провинции (вы также можете программно добавить фильтр в конвейер), почему бы не выполнить агрегирование?

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

Это вернет массив объектов со следующей структурой:

[
  {
    "_id" : "provinceName",
    "count" : 6
  },
  ....
]
0 голосов
/ 27 февраля 2020

Вы можете прикрепить обратный вызов к обещаниям в первом l oop:

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);
});
...