Node.js Mongoose承诺迷路了

时间:2017-09-26 09:06:16

标签: javascript node.js mongoose promise bcrypt

我有一个带有mongoDB的Node.js API。有一条创建用户并需要哈希密码的路由,为此我使用了bcryptjs包。

路线如下:

router.route('/user')

    .post(function(req, res) {
        if(req.body.password === req.body.passwordConfirm) {
            userManager.addUser(req.body)
                .then(function(response) { // waiting for the result of the mongoDB save
                    res.send({data:response});
                });
         } else {
             res.send({err:'passwords do not match'});
         }
     })

和userManager.addUSer:

this.addUser = function(userobject) {
    bcrypt.genSalt(10, function(err, salt) { // generate a salt
        if(err !== null) {
            console.log(err);
        } else {
            bcrypt.hash(userobject.password_hash, salt, function(err, hash) { // hash pw
                if(err !== null) {
                    console.log(err);
                else {
                    userobject.password_hash = hash; // store hash in user obj
                    var user = new User(userobject);
                    return user.save().catch(function(err){ // save user in mongoDB
                        console.log(err);
                    });
                }
            });
        }
    });
};

我收到错误消息:"无法读取属性'然后' of undefined",它告诉我,我没有收到addUser的承诺。我看起来和bcryptjs遗憾地不使用承诺,但是,mongoose确实如此。 (补充一点:

var mongoose = require('mongoose').Promise = Promise;

没有帮助)

我尝试用拒绝和解决方法将函数包装在一个promise中,但是这会给出这个错误:" TypeError:Promise resolver undefined不是函数"。

我如何得到mongoose的save()函数返回到post route中的.then()的承诺?我尝试在两个bcrypt函数前面添加return但是那个也没有...

欢迎任何建议!

3 个答案:

答案 0 :(得分:1)

您的addUser函数会向其调用方返回承诺。您正在使用return回调函数执行bcrypt.hash,但这与addUser的返回值无关。

看起来addUser必须使用一些非启用Promise的API,因此您仍然坚持使用new Promise,类似这样的内容(请参阅***条评论) :

this.addUser = function(userobject) {
    return new Promise(function(resolve, reject) { // ***
        bcrypt.genSalt(10, function(err, salt) { // generate a salt
            if(err !== null) {
                reject(err);                       // ***
            } else {
                bcrypt.hash(userobject.password_hash, salt, function(err, hash) { // hash pw
                    if(err !== null) {
                        reject(err);               // ***
                    else {
                        userobject.password_hash = hash; // store hash in user obj
                        var user = new User(userobject);
                        resolve(user.save());      // *** save user in mongoDB
                    }
                });
            }
        });
    });
};

另请注意,我没有addUser只是吞咽错误;相反,它们会传播给呼叫者。调用者应该处理它们(即使"处理"只是记录)。

答案 1 :(得分:1)

您不会从this.addUser返回承诺,您必须将基于bcrypt的回复转换为承诺。您可以转换整个bcrypt API以支持基于Promise的功能,例如使用蓝鸟图书馆的promisifyAll,或者像{1}}一样手动执行:

new Promise

或那样:

this.addUser = function(userobject) {
  return new Promise((resolve, reject) => {
      bcrypt.genSalt(10, (err, salt) => {
        if (err) {
          reject(err);
        } else {
          bcrypt.hash(userobject.password_hash, salt, function(err, hash) {
            if (err) {
              reject(err)
            } else {
              resolve(hash)
            }
          })
        }
      });
    })
    .then(hash => {
      userobject.password_hash = hash; // store hash in user obj
      var user = new User(userobject);
      return user.save() // save user in mongoDB
    })
    .catch(function(err) {
       console.log(err);
    });
}

答案 2 :(得分:0)

在对bcryptjs的更改日志中进行了一些挖掘后,我发现他们添加了promises但没有更新文档..如果省略回调,genSalt en哈希方法将返回一个promise。这将转化为:

this.addUser = function(userobject) {
    return bcrypt.genSalt(10).then((salt) => {
        return bcrypt.hash(userobject.password, salt).then((hash) => {
            userobject.password_hash = hash;
            var user = new User(userobject);
            return user.save();
        });
    });
};