I imagine using bluebirds promisify, you would promisify bcrypt.compare like so (you don't HAVE to use the Async part of the name)
let compareAsync = Promise.promisify(bcrypt.compare);
because userObject
in the first .then needs to be used in the second .then, you can't simply chain the .then's by returning compareAsync, because then the next .then wont have access to userObject
one fix, is to use a variable that will be in scope for both .then's (but ugh)
username = username.toUpperCase();
let text = "SELECT * FROM users WHERE username = $1";
let values = [username];
let uo; //hacky the outer scoped variable
database.one(text, values).then(function (userObject) {
uo = userObject;
return compareAsync(password, userObject.password);
}).then(function(same) {
if (!same) {
throw new Error("Password mismatched!");
}
const serializeObject = {_id: uo._id};
return next(null, serializeObject);
}).catch(function (err) {
return next(err, null);
});
another (in my opinion cleaner) option is a nested .then
username = username.toUpperCase();
let text = "SELECT * FROM users WHERE username = $1";
let values = [username];
database.one(text, values).then(function (userObject) {
return compareAsync(password, userObject.password)
// [optional] following three lines to generate a "nicer" error for compare failure
.catch(function(err) {
throw "bcrypt.compare failed";
})
// nested .then to pass on the userObject and same at the same time
.then(function (same) {
return { same: same, userObject: userObject };
});
}).then(function (result) {
let same = result.same,
userObject = result.userObject;
if (!same) {
throw new Error("Password mismatched!");
}
let serializeObject = { _id: userObject._id };
return next(null, serializeObject);
}).catch(function (err) {
return next(err, null);
});
NOTE: bluebird has a promisifyAll function ... that promisifies functions in an object, and adds (by default) the Async
postfix to the function name - I believe you can decide on a different postfix name, but the documentation will tell you more
when promisifying a single function, you declare the name yourself - the above could've easily been
let trumpIsBigly = Promise.promisify(bcrypt.compare);
then you would just use trumpIsBigly
where the code has compareAsync
One last possibility
A hand rolled promisified compareAsync (lifted mostly from vitaly-t's answer but with additions)
function compareAsync(password1, password2, inValue) {
return new Promise(function (resolve, reject) {
bcrypt.compare(password1, password2, function (err, same) {
err = err || (!same && new Error("Password mismatched!"));
if (err) {
reject(err);
} else {
resolve(inValue);
}
});
});
}
Now compareAsync will resolve to the incoming value inValue
only if there's no error, AND same is true
username = username.toUpperCase();
let text = "SELECT * FROM users WHERE username = $1";
let values = [username];
database.one(text, values).then(function (userObject) {
return compareAsync(password, userObject.password, userObject)
}).then(function (userObject) {
let serializeObject = { _id: userObject._id };
return next(null, serializeObject);
}).catch(function (err) {
return next(err, null);
});
Which makes the "chain" very simple!
bcrypt.compare
for you – AdulterantI am not sure if it possible to turn this code to promise base
any code can be turned into promises, and thepromisify
solution for yourbcrypt
module is the easiest one. – Caber