mongoDB promise gets returned too early [closed]

2019-01-24 23:53发布

问题:

I just started trying to implement Promises on my Node.js app. Right now i'm checking if a user and password exists then using mongodb to look them up if user isn't found it sets promise.reject() but it is returning the promise too early and it's still in the pending state. If anyone can help or give me ideas on how to refactor it would be much appreciated.

https://gist.github.com/joshbedo/8957056

回答1:

It is the expected behavior it returns the promise while it is still in the pending state.

You should use then() to check for promise resolution.

Another thing is that you should not use the traditional mongo interface when starting to work with promises, but rather promisify all method of the Collection prototype, so you can return the Promise created by the mongo find method with its chain of thenable. Otherwise I don't see the point of using promises. The way you do does not reduce the amount of code you have to write.

By the way, IMHO you should use bluebird rather than Q, as it is at the moment the only promise library which is not extremely slow.

Example :

in db.js

var mongoClient = require('mongodb').MongoClient;
var collection  = require('mongodb').Collection;

var Promise     = require('bluebird');

// We promisify everything. Bluebird add ***Async function which return promises.
Promise.promisifyAll(collection.prototype);
Promise.promisifyAll(mongoClient);

//In mongodb cursor is not built from protoype I use to promisify it each time. Not necessary if you don't use cursors.
collection.prototype._find = collection.prototype.find;
collection.prototype.find = function() {
  var cursor = this._find.apply(this, arguments);
  cursor.toArrayAsync = Promise.promisify(cursor.toArray, cursor);
 return cursor;
};

//then you connect to the DB and exports your collections...

elsewhere, taking your example :

this.loginUser = function(user) {
  var userid = user.userid,
  var password = (user.password) ?
    crypto.createHash("md5").update(user.password).digest("hex"):
    undefined
  var rememberme = user.rememberme;

  if(userid && password) {
    // we directly return the promise from mongodb, that we chain with a then
    return db.users.findOneAsync({ email: userid, password: password }) // return a promise that we chain
    .then(function(user) { // that we chain
      if(user) {
        var logincode = uuid.v4(),
        var token = jwt.encode({email: userid, password: password}, secret);

        if(rememberme) {
          res.cookie("clogincode", logincode, { magAge: 900000 } );
        }
        return user;  // return in a then callback will just resolve the promise
      } else {
        throw  new Error('User not found'); // throwing in a then callback will just reject the promise
      }
    }); // end of the then, then return a promise that we return (with the return keyword above)
  } else {
    return Promise.reject("Username or Password was not entered"); // this is the only case where we have to actually create a promise ourself
  }
}