Почему мой асинхронный код работает в контроллере, а не в модели? - PullRequest
0 голосов
/ 02 мая 2019

Я использую 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.log(match);
  } catch(error) {
    console.log(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.

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

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

Ответы [ 2 ]

1 голос
/ 02 мая 2019

Мне потребовалось некоторое время, но я наконец смог понять, что я сделал не так. Я использовал 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 ...
0 голосов
/ 02 мая 2019

Насколько я использовал 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.log(match);
      resolve(match)
    } catch(error) {
      console.log(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,
  })
}

В качестве альтернативы вы можете отклонить обещание, если match равно false, и оценить отклонение в улове

...