Асинхронность/Ожидание не работает с мангустом findOne

#javascript #mongoose #async-await

Вопрос:

Я пытаюсь получить переменную ответа, но когда вызывается функция обратного вызова, все, что я получаю, — это пустая переменная. Async/await, похоже, не работает для функции findOne, так как я получаю значения после вызова обратного вызова.

 function byClanTag(tag, callback) {
  clashApiClient
    .clanByTag(tag)
    .then((response) => {
      var reply = "";
      console.log("1");
      response.memberList.forEach(async (member) => {
        console.log("2");
        await Player.findOne({ playerTAG: member.tag }, (err, player) => {
          if (err) {
            console.log(err);
            callback("Error: ", err);
          }
          if (!player) {
            console.log("3");
            reply = reply   member.name   ": "   "Strike information doesn't exist.n";
          } else {
            reply = reply   member.name   ": "   player.strikeCount   "Strikes.n";
          }
        });
      });
      console.log("4");
      callback("```"   response.name   " :   nn"   reply   "```");
    })
    .catch(() => callback("Error: Something went wrong while getting data!"));
}
 

Ожидаемый вывод журнала равен 1 (23)*n раз 4, но в итоге я получаю 1 (2)*n раз 4 (3)*n раз

Комментарии:

1. Вы должны использовать for ...of цикл вместо forEach цикла, чтобы обещание работало правильно

Ответ №1:

Вы либо используете обратные вызовы, либо используете Обещания. Вы пытаетесь сделать и то, и другое, когда используете await Player.findOne({ ... }, (err, player) => { ...}) .

Вы должны обновить строку, чтобы она была const player = await Player.findOne({ ... }) . Плюс, как предложил Рифат в комментарии, используйте for ...of цикл, чтобы обещание работало правильно.

Комментарии:

1. Я согласен, код выглядит очень запутанным как с обещанием, так и с обратным вызовом. Трудно читать и отлаживать

Ответ №2:

Имеет смысл использовать Promise.all для выполнения всех запросов параллельно, а не последовательно, как это:

 function byClanTag(tag, callback) {
  clashApiClient
    .clanByTag(tag)
    .then((response) => {
      const pendingPromises = response.memberList.map((member) => Player.findOne({ playerTAG: member.tag })
      return Promise.all(pendingPromises)
    })
    .then((arrayOfResults) => {....})
    .catch(() => callback("Error: Something went wrong while getting data!"));
}
 

Однако, чтобы снизить нагрузку на базу данных, правильным решением будет получить данные по массиву идентификаторов в одном запросе.