【问题标题】:How to call a function returning a promise on a result of a promise?如何调用一个函数返回一个承诺结果的承诺?
【发布时间】:2017-05-16 11:19:56
【问题描述】:

我有一个基本的猫鼬身​​份验证,使用 bcryptjs 来散列密码。 bcrypt 和 mongoose 都返回承诺。在我的 routes.js 中,我有以下脚本在数据库中找到用户后卡住了:

routes.post('/auth', (req, res)=> {
    User.findOne({'local.username': req.body.username})
        .then(
            user=> Promise.all([user, user.validate(req.body.password)])
        )
        .then(
            results => {
                console.log(results);
                res.json({token: jwt.sign({id: results[0]._id}, config.secret)});
            }
        )
        .catch(
            err=> console.log(err)
        );
});

如您所见,我找到了用户,然后尝试调用其 validate 方法(该方法被调用),但它不会解决承诺,也不会引发错误。在定义我的 UserSchema 的 user.js 中,我有这段代码来比较密码:

UserSchema.methods.validate = function (password) {
    return bcrypt.compare(password, this.local.password);
};

这被调用了,但返回的承诺似乎消失了,它没有被解析,结果变量永远不会被记录。

还有一件事,如果我将用户验证代码编辑为:

UserSchema.methods.validate = function (password) {
    return bcrypt.compare(password, this.local.password).then(
        results => {
            console.log(results)
        }
    )
};

我真的登录到控制台,所以它必须工作,但我不想在这里解决我的承诺,我想在我的路由器中附加 .then(...),这不可能吗?

我做错了什么?

更新:

如果我将 compare 方法放在 routes.js 中它可以工作,但这不是我想要做的,我想将它保留在 user.js 中,但我认为这可能会指出我仍然存在的问题看不到。我想我必须立即按承诺调用 then(),但我不明白为什么。

 User.findOne({'local.username': req.body.username})
        .then(
            user=> Promise.all([user, bcrypt.compare(req.body.password,user.local.password)])
        )
        .then(
            results => {
                console.log(results);
                res.json({token: jwt.sign({id: results[0]._id}, config.secret)});
            }
        )
        .catch(
            err=> console.log(err)
        );

【问题讨论】:

  • Promise.all([user, user.validate(req.body.password)]) 应该是Promise.all([Promise.resolve(user), user.validate(req.body.password)])
  • @MatthieuLemoine 是的,这似乎是合理的,但尝试过它并不起作用:S
  • 不确定,但我认为您的验证方法也应该解决承诺。
  • 仅在validate 函数中尝试return bcrypt.compare(password, this.local.password)
  • @MatthieuLemoine 不需要,Promise.resolvePromise.all 隐式调用。

标签: javascript node.js mongoose es6-promise


【解决方案1】:

首先为什么在这里使用 Promise.all?特别是我不认为需要做类似Promise.resolve(user) 的事情。在不知道user.validate 是如何工作的情况下,我会这样写

routes.post('/auth', (req, res)=> {
    let userId

    User.findOne({'local.username': req.body.username})
    .then(user => {
      userId = user._id
      return user.validate(req.body.password)
    })
    .then(results => {
      console.log(results);
      res.json({token: jwt.sign({id: userId}, config.secret)});
    })
    .catch(err => console.log(err))
});

【讨论】:

  • 我试过这个。它对我不起作用,这就是我后来尝试 Promise.all() 的原因,它也不起作用
  • 为什么是Promise.all?因为那是much better pattern 而不是the ugly global userId variable
  • 会部分同意你的看法。会争论什么更丑陋,为路由处理程序创建作用域变量或在不需要时创建一个承诺。
【解决方案2】:

我发现问题出在猫鼬身上。它包装了模块方法,并承诺在某处“迷路”。解决方案是使用同步比较方法,或提供回调。

我也在 github 上创建了一个问题: https://github.com/Automattic/mongoose/issues/4856

【讨论】:

    【解决方案3】:

    你没有对你在 then 中调用的 Promise.all 做任何事情。

    代替

    user=> Promise.all([user, user.validate(req.body.password)])
    

    你应该这样做:

    user.validate(req.body.password)
    .then(results => {
        // Do stuff with results here...
    });
    

    【讨论】:

    • 我认为这是一样的,因为 Promise.all() 返回一个由 .then() 处理的承诺
    • 他正在从回调中返回Promise.all(…),这就够了。
    猜你喜欢
    • 2015-11-27
    • 1970-01-01
    • 2015-06-05
    • 2019-07-09
    • 2017-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多