Проблема с подсчетом очков викторины NodeJS

Поэтому я сделал веб-сайт с викториной, используя «стек MEN» (без React), если его можно так назвать. Ссылка на репо здесь.

При локальном тестировании приложения викторина работает должным образом. Без вопросов. Оценка производится после того, как пользователь отправляет форму. У меня есть несколько ключевых слов для каждого вопроса, и при отправке я проверяю, ввел ли пользователь какие-либо ключевые слова, которые я установил. Код для этого можно увидеть ниже.

router.post("/submit", (req, res) => {
  let sub = Object.values(req.body);
  let ans = [];
  sub.forEach((opt, idx) => {
    opt = opt.toLowerCase();
    ans[idx] = opt.split(" ");
  });
  let score = 0;
  ans.forEach(async (opt, idx) => {
    const corr = await Question.findOne({
      index: idx,
    });
    corr.answer = corr.answer.toLowerCase();
    let correct = corr.answer.split(" ");
    let res = correct.some((val) => {
      return opt.indexOf(val) >= 0;
    });
    if (res) {
      score += 10;
    }
  });
  setTimeout(async () => {
    const user = await User.findByIdAndUpdate(req.user.id, {
      score,
      completed: true,
      submittedAt: Date.now(),
      answers: sub,
    });
  }, 1000);

  // console.info(req.user.id);
  res.render("finished");
});

Как видите, мне пришлось использовать setTimeout для подсчета очков, так как без него это не работало. Я предположил, что это вызвано асинхронным характером вычислительной функции. Если вы можете предложить лучшую альтернативу, это будет здорово. Ниже приведен пример одного вопроса и его ключевых слов:

{
    description: "A company was started by the Maharaja of Mysore, Nalvadi Krishnaraja W..."
    answer: "vote voting voter voters indelible ink"
    index: 3
    __v: 0
}

После запуска викторины у нас было около 150 участников. При подаче возникла одна проблема; не все оценки пользователей рассчитывались правильно. Некоторые из них были связаны с разными ответами на ключевые слова, но я не смог найти причину для других.

Один из таких необъяснимых случаев был следующим. На первом изображении представлена ​​работа в самом викторине, на втором — тест, который я сделал только что, используя те же ответы, что и у этого участника:

Фактическая подача:

{
    score: 0
    completed: true
    answers: [
      "Trump Towers", "Shakuntala Devi", "Sir", "Voter ink", "",
      "Indian Constitution", "Saera jahe se accha", "Sunfeast open",
      "Dunlop", "Robert Clive", "APJ Abdul Kalam", 
      "Signing the ordinance in Indian emergency",
      "Indian nuclear operation in pokhran", "Mohammad Salim",
      "Swami Vivekananda", "Bubble wrap", "", "Inquilab",
      "Chintaman ganesh temple", "Jamtara"
    ]
}

Мой тест:

{
    score: 140
    completed: true
    answers: [
      "Trump Towers", "Shakuntala Devi", "Sir", "Voter ink", "",
      "Indian Constitution", "Saera jahe se accha", "Sunfeast open",
      "Dunlop", "Robert Clive", "APJ Abdul Kalam", 
      "Signing the ordinance in Indian emergency",
      "Indian nuclear operation in pokhran", "Mohammad Salim",
      "Swami Vivekananda", "Bubble wrap", "", "Inquilab",
      "Chintaman ganesh temple", "Jamtara"
    ]
}

Как видите, ответы абсолютно одинаковы. Даже случаи одинаковые. Правильная оценка для вышеуказанных представлений составляет 140, как я получил выше.

Я предполагаю (дикое предположение), что проблема может быть из-за setTimeout. Любая альтернатива этому методу подсчета очков будет полезна.

Буду благодарен за любую помощь по этому поводу. Заранее спасибо.

🤔 А знаете ли вы, что...
JavaScript можно использовать для создания видеоигр, как 2D, так и 3D, с использованием библиотеки Three.js.


152
1

Ответ:

Решено

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

Есть и другие способы решить эту проблему (на ум приходит Promise.all), одна из возможностей — использовать асинхронную версию forEach, а затем дождаться результата перед вызовом User.findByIdAndUpdate (теперь без тайм-аута). Я не использовал его, но быстрый поиск async forEach выдал статью, которая выглядит многообещающе.

Это, вероятно, потребует, чтобы обратный вызов также передавался в router.post асинхронно.

Если этого не произойдет, я бы рассмотрел методы создания минимального воспроизводимого примера. Этот процесс часто помогает вам найти ответ самостоятельно. А когда это не так, это дает потенциальным помощникам что-то маленькое, чтобы пожевать.