为啥我的异步代码在控制器中有效,但在模型中无效?

Posted

技术标签:

【中文标题】为啥我的异步代码在控制器中有效,但在模型中无效?【英文标题】: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 【参考方案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 即可。感谢您的诚实尝试。它让我走上了正轨。

以上是关于为啥我的异步代码在控制器中有效,但在模型中无效?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的启动 OpenOffice 服务的调用在开发中有效,但在服务器上无效?

为啥此 python 代码在 pyspark 中有效,但在 spark-submit 中无效?

将 ansi 打印到 windows cmd 在 IPython 中有效,但在其他任何地方都无效。为啥?

为啥 CString::LoadString 在我的应用程序的主模块(.exe)中有效,但在我的 extensionDLL 中无效?

为啥此查询字符串在 Access 中有效,但在 C# 中无效?

模型方法在 Bookings 模型中有效,但在事件和票证中无效