Почему даже после использования async await для нескольких звонков все равно получил пустой ответ? - PullRequest
0 голосов
/ 27 сентября 2018

Вот простой маршрут узла, в котором вызывается асинхронный api.

Что нужно, это return data после зацикливания.Но он возвращает пустой объект.

try {
  const array = ["brunch", "lunch", "crunch"]
  const data = {}
  array.map(async(d) => {
    const venue = await Venue.find({ "category": { "$in": [d] }})
    data[d] = venue
  })
  return data
} catch(err) {
  throw err
}

Пожалуйста, помогите мне достичь этого

Ответы [ 3 ]

0 голосов
/ 27 сентября 2018

Хотя подход @chridam довольно уникален и, возможно, более эффективен, если вы хотите придерживаться цикла.

Существует два подхода.Вы хотите, чтобы все операции выполнялись параллельно или последовательно.

Если Параллельно , вам придется использовать Promise.all.

try {
  const array = ["brunch", "lunch", "crunch"]
  const data = {}
  await Promise.all(array.map(async(d) => {
    data[d] = await Venue.find({ "category": { "$in": [d] }})
  }))
  return data
} catch(err) {
  throw err
}

Если series , вам придется использовать простой цикл for.

array.map(async(d) => {}) делает внутренний вызов БД асинхронным и не ожидает операции.нормальный for цикл будет синхронным.

try {
  const array = ["brunch", "lunch", "crunch"]
  const data = {}
  for (d of array) {
    data[d] = await Venue.find({ "category": { "$in": [d] }})
  }
  return data
} catch(err) {
  throw err
}
0 голосов
/ 27 сентября 2018

Проблема в том, как вы используете async-await.Он находится внутри Array.prototype.map, что делает функцию .map асинхронной, и поэтому основной поток никогда не ждет завершения цикла и перехода к следующему оператору и возвращает data, что составляет просто {}.

try {
  const array = ["brunch", "lunch", "crunch"]
  const data = {};

  // here's the issue async is callback function to map, due to which never waited for map function to finished.
  array.map( async(d) => {
    const venue = await Venue.find({ "category": { "$in": [d] }})
    data[d] = venue;
  });

  return data;
} catch(err) {
  throw err
}

Измените код на это:

(async function () {
    try {
      const array = ["brunch", "lunch", "crunch"]
      const data = {};

      array.map( d => {
        const venue = await Venue.find({ "category": { "$in": [d] }})
        data[d] = venue;
      });

      return data;

    }
    catch(err) {
      throw err
    }
})();

То, что вы сделали, похоже на это

function main () {
    return new Promise ( resolve => {
        setTimeout( () => {
            console.log("First");
            resolve(true);
        },5000 );
    });
}

(async function () {
    await main();

    console.log("Second")
})();

console.log("Third");
// Third
// First
// Second
0 голосов
/ 27 сентября 2018

Существует лучший способ получить желаемый результат с MongoDB, и нет необходимости в цикле, используйте структуру агрегации, где вы можете запустить следующий конвейер, который использует $facet как

try {
    const array = ["brunch", "lunch", "crunch"]
    const facet = array.reduce((acc, cur) => {
        acc[cur] = [{ "$match": { "category": cur } }]
        return acc
    }, {})
    const pipeline = [
        { "$match": { "category": { "$in": array } } },
        { "$facet": facet }
    ]
    const results = await Venue.aggregate(pipeline).exec()
    const data = results[0]

    return data
} catch(err) {
    throw err
}

Вы также можете сгруппировать документы по ключу категории и $push документов по группе, а затем преобразовать в ключи документав $replaceRoot с $arrayToObject

try {
    const array = ["brunch", "lunch", "crunch"]
    const pipeline = [
        { "$match": { "category": { "$in": array } } },
        { "$group": { 
            "_id": "$category",
            "data": { "$push": "$$ROOT" }
        } },
        { "$group": {
            "_id": null,
            "venues": {
                "$push": {
                    "k": "$_id",
                    "v": "$data"
                }
            } 
        } },
        { "$replaceRoot": {
            "newRoot": { "$arrayToObject": "$venues" }
        } }
    ]
    const results = await Venue.aggregate(pipeline).exec()
    const data = results[0]

    return data
} catch(err) {
    throw err
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...