【问题标题】:Why does my async code work in the controller but not in the model?为什么我的异步代码在控制器中有效,但在模型中无效?
【发布时间】:2019-09-21 05:44:09
【问题描述】:

我正在使用 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,
  })
}

当我调试它时,matchundefined

如果我在控制器中进行比较,它会按预期工作。我宁愿比较在模型文件中。我在这里做错了什么?

我是 async/await 代码的新手,但我已经成功地使用它在同一个项目中实现了几个其他控制器方法。

【问题讨论】:

  • 尽管将其命名为returnValue...
  • @jonrsharpe 该评论显示了我的原始结构。添加了返回值,因此我可以在其中设置一个断点并查看 bcrypt 比较方法返回的值。
  • 你有没有试过在函数调用前加上await

标签: node.js express async-await sequelize.js


【解决方案1】:

我花了一段时间,但我终于能够弄清楚我做错了什么。我使用 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 ...

【讨论】:

    【解决方案2】:

    据我在 js 中使用 async/await 并理解它,您应该在您的 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,
      })
    }
    

    作为替代方案,如果匹配为假,您可以拒绝承诺并评估 catch 中的拒绝

    【讨论】:

    • 我看不出上面的内容如何表明密码匹配失败。只有抛出错误才会失败。我错过了什么吗?
    • 对不起,我完全误解了 bcrypt.compare 的用法及其返回值。我调整了代码示例。
    • 如果您在下面看到我的解决方案,bcrypt.compare 如果没有提供回调,则已经返回了一个承诺。我想多了。我只需要在我的控制器中返回该承诺和await 即可。感谢您的诚实尝试。它让我走上了正轨。
    猜你喜欢
    • 2020-08-09
    • 1970-01-01
    • 2019-05-23
    • 1970-01-01
    • 2019-09-10
    • 2020-11-14
    • 2011-09-09
    • 1970-01-01
    • 2012-09-16
    相关资源
    最近更新 更多