Node.js Mongoose Promise 迷路了

Posted

技术标签:

【中文标题】Node.js Mongoose Promise 迷路了【英文标题】:Node.js Mongoose Promise getting lost 【发布时间】:2018-03-07 10:11:20 【问题描述】:

我有一个带有 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);
                    );
                
            );
        
    );
;

我收到一条错误消息:“无法读取未定义的属性 'then'”,这告诉我我没有收到来自 addUser 的承诺。我看了看,遗憾的是 bcryptjs 不使用承诺,但是,猫鼬会。 (添加这个:

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

没有帮助)

我尝试用reject 和resolve 将函数包装在一个promise 中,但这给出了这个错误:“TypeError: Promise resolver undefined is not a function”。

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

欢迎提出任何建议!

【问题讨论】:

你没有从你的this.addUser返回一个Promise。 要清楚,你不会从this.addUser返回任何东西 @Jaromanda X 是的,我现在明白了,我是 Promise 的新手,我想我迷失了不支持 Promise 的 API.. 【参考方案1】:

您的addUser 函数永远不会将承诺返回给它的调用者。您正在通过bcrypt.hash 回调函数执行return,但这与addUser 的返回值无关。

看起来addUser 必须使用一些未启用 Promise 的 API,因此您只能使用 new Promise,类似这样的事情(请参阅 *** cmets):

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 只是吞咽错误;相反,它们被传播给调用者。调用者应该处理它们(即使“处理”只是记录)。

【讨论】:

【参考方案2】:

您不会从 this.addUser 返回 Promise,您必须将基于 bcrypt 的回调转换为 Promise。您可以使用例如转换整个 bcrypt API 以支持基于 Promise 的函数。蓝鸟库的promisifyAll,或者像这样使用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);
    );

或者那样:

this.addUser = function(userobject) 
  return new Promise((resolve, reject) => 
      bcrypt.genSalt(10, (err, salt) => 
        if (err) 
          reject(err);
         else 
          resolve(salt);
        
      );
    )
    .then(salt => 
      return new Promise((resolve, reject) => 
        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);
    );

【讨论】:

【参考方案3】:

在对 bcryptjs 的更改日志进行更多挖掘后,我发现他们添加了 Promise,但没有更新文档。如果省略回调,则 genSalt en hash 方法将返回一个 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();
        );
    );
;

【讨论】:

以上是关于Node.js Mongoose Promise 迷路了的主要内容,如果未能解决你的问题,请参考以下文章

Node js,使用带有Q promise的mongoose不会调用reject函数

[js高手之路]Node.js+jade+express+mongodb+mongoose+promise实现todolist

在 Node.js + Express 中使用 Promise 处理错误

使用 Node.Js 和 Promises,你如何返回一个已经实现的 Promise? [复制]

使用 Node.Js 和 Promises,你如何返回一个已经实现的 Promise? [复制]

异步函数不等待Promise