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.
Asked
Active
Viewed 3,227 times
2
-
1as a side note: use something stronger than md5 hashing for passwords and I wouldn't rely on uuid for the confirmation code either. – mnemosyn Feb 12 '14 at 15:59
-
yeah it's just to get it running plus i didn't want to expose my security module :p – Josh Bedo Feb 12 '14 at 16:15
-
Make sure you return after the first defer.reject(err) otherwise defer.reject() will be called again in defer.reject("User not found") – Hector Correa Feb 12 '14 at 16:17
1 Answers
5
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
}
}

Dmitry Minkovsky
- 36,185
- 26
- 116
- 160

jillro
- 4,456
- 2
- 20
- 26
-
Do you happen to know what IcedCoffeeScript's await and defer uses? yeah I want it to check if variables are set, then query database, then check if a result is fulfilled or rejected. It seems like I'm adding a lot more to my code base trying to achieve that functionality. – Josh Bedo Feb 12 '14 at 16:17
-
-
I personnaly use bluebird's promisify method which basically can promisify any library using node style callbacks. I dont know if Q has the same kind of utility fonctions. – jillro Feb 12 '14 at 17:04
-
-
3
-
For future visitors, also see http://stackoverflow.com/q/23771853/438992. – Dave Newton Aug 13 '14 at 22:35