Reputation:
I'm confused on how this chaining for promises work, I'm still fairly new to promises and js in general so excuse me
line three, return user.findOne({email}).then((user) => {
, i'm just confused about how returning this promise does anything since it returns a other promise inside the .then()
UserSchema.statics.findByCredentials = function(email, password){
user = this;
return user.findOne({email}).then((user) => {
if (!user){
return Promise.reject();
}
return new Promise((resolve, reject) => {
bcrypt.compare(password, user.password, (err, res) => {
if (res){
resolve(user);
}else{
reject()
}
});
});
});
}
the findByCredentials model method being used in an express app
app.post("/users/login", (req, res) => {
var body = _.pick(req.body, ["email", "password"]);
User.findByCredentials(body.email, body.password).then((user) => {
res.send(body)
}).catch((e) => {
res.send("!");
})
A simpler example I just created, this part
return plus(1).then((res) => {
return new Promise((resolve, reject) => { is the problem i'm having trouble understanding
function plus(a) {
return new Promise((resolve, reject) => {
resolve(a + 1);
});
}
function test() {
return plus(1).then((res) => {
console.log(res);
return new Promise((resolve, reject) => {
resolve("Test");
});
});
}
test().then((res) => {
console.log(res);
});
Upvotes: 1
Views: 153
Reputation: 22939
As @Bergi said in the comment of your OP, the true power or Promises
comes from returning them in the then
of other Promises
.
bcrypt.compare
function uses callbacks to signal that it's done, so you need that function convert to a Promise
. This is easy to do. Just wrap the callback-style code in a Promise and resolve
the result
of the callback or reject
if the callback is called with an err
.
const comparePassword = (a, b) => {
return new Promise((resolve, reject) => {
bcrypt.compare(a, b, (err, result) => {
// Reject if there was an error
// - rejection is `return`-ed solely for stopping further execution
// of this callback. No other reason for it.
if (err) return reject(err)
// Resolve if not.
resolve(result)
})
})
}
... and then we can chain properly:
UserSchema.statics.findByCredentials = function(email, password) {
// Outer Promise:
// - Will eventually resolve with whatever the result it's inner
// promise resolves with.
return user.findOne({ email })
.then((user) => {
// Inner Promise:
// - Will eventually resolve with `user` (which is already
// available here), given that the password was correct,
// or
// reject with the bcrypt.compare `err` if the password was
// incorrect.
return comparePassword(password, user.password)
.then((result) => {
// This `then` belongs to the comparePassword Promise.
// - We use this so we can make sure we return the `user` we picked up
// from the previous `user.findOne` Promise.
// - This ensures that when you chain a `then` to this Promise chain
// you always get the `user` and not the result of `comparePassword`
return user
})
})
}
The key here is that whatever you return
within a .then()
is going to be passed as an argument to the next chained .then()
.
bcrypt.compare
already returns a Promise
, so we could have avoided the whole hassle of wrapping it into a Promise. I've intentionally used it with callbacks to illustrate how you should handle callback-style code in a Promise chain.Upvotes: 3