Почему мой асинхронный код работает в контроллере, но не в модели?

Я использую bcrypt 3.0.6. У меня есть следующий код в моем файле Model:

User.prototype.validPassword = async function(password) {
  try{
    // original code:
    // return await bcrypt.compare(password, this.password);
    const match = await bcrypt.compare(password, this.password);
    console.info(match);
  } catch(error) {
    console.info(error);
    return false;
  }
};

и я вызываю его из моего контроллера:

try {
  if (!req.body.userName || !req.body.password) throw "Invalid Login"
  user = await User.findOne({
    where: { userName: req.body.userName }
  })
  if (!user) throw "Invalid login"
  const match = user.validPassword(req.body.password);
  // const match = await bcrypt.compare(req.body.password, user.password);
  if (!match) throw "Invalid login";
  // build token
  ...
});
} catch(error) {
  res.status(500).json({
    "msg": "Server Error",
    "error": error,
  })
}

Когда я его отлаживаю, match становится undefined.

Если я сравниваю в контроллере, он работает так, как ожидалось. Я бы предпочел, чтобы сравнение было в файле модели. Что я здесь делаю неправильно?

Я новичок в коде async/await, но я успешно использовал его для реализации нескольких других методов контроллера в том же проекте.

Несмотря на название returnValue...

jonrsharpe 02.05.2019 18:46

@jonrsharpe Комментарий показывает мою оригинальную конструкцию. возвращаемое значение было добавлено, чтобы я мог поставить точку останова и увидеть значение, возвращаемое методом сравнения bcrypt.

cstrutton 02.05.2019 19:20

Вы пробовали ставить await перед вызовом функции?

pyriand3r 02.05.2019 20:09
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
150
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Насколько я использовал async/await в js и понял это, вы должны вернуть обещание в свой метод validPassword. Поскольку метод использует await, он сам по себе является асинхронным методом, который работает вне нормального потока контроллера.

Поэтому, основываясь на вашем коде, я бы рекомендовал изменить его на что-то похожее на это:

User.prototype.validPassword = function(password) {
  return new Promise(async function (resolve, reject) {
    try{
      // original code:
      // return await bcrypt.compare(password, this.password);
      const match = await bcrypt.compare(password, this.password);
      console.info(match);
      resolve(match)
    } catch(error) {
      console.info(error);
      reject();
    }
  }
};

и контроллер:

try {
  if (!req.body.userName || !req.body.password) throw "Invalid Login"
  user = await User.findOne({
    where: { userName: req.body.userName }
  })
  if (!user) throw "Invalid login"
  try {
    const match = await user.validPassword(req.body.password);
    If (!match) throw "invalid login";
    // build token
  } catch (err) {
    throw "Server error";
  }

  ...
});
} catch(error) {
  res.status(500).json({
    "msg": "Server Error",
    "error": error,
  })
}

В качестве альтернативы вы можете отклонить обещание. Если совпадение ложно, и оценить отклонение в улове.

Я не понимаю, как приведенное выше может указывать на неудачное совпадение пароля. Он потерпит неудачу только в том случае, если выдаст ошибку. Я что-то пропустил?

cstrutton 02.05.2019 21:58

Извините, я совершенно не понял использование bcrypt.compare и его возвращаемое значение. Ich скорректировал примеры кода.

pyriand3r 03.05.2019 01:47

Если вы видите мое решение ниже, bcrypt.compare уже возвращает обещание, если обратный вызов не предоставлен. Я слишком много думал об этом. Мне просто нужно было вернуть это обещание и await за результат в моем контроллере. Спасибо за честную попытку. Это поставило меня на правильный путь.

cstrutton 03.05.2019 13:37
Ответ принят как подходящий

Мне потребовалось некоторое время, но я, наконец, смог понять, что я сделал неправильно. Я слишком много использовал async/await. Следующий код работает так, как я ожидал:

User.prototype.validPassword = function(password) {
  return bcrypt.compare(password, this.password);
};

Я упустил тот факт (или, точнее, важность того факта), что bcrypt.compare возвращает обещание. Мне просто нужно было вернуть это обещание и await решить его.

И в контроллере:

  if (!user) throw "Invalid login";
  const match = await user.validPassword(req.body.password);
  if (!match) throw "Invalid login";
  // build token ...

Другие вопросы по теме