如何链接承诺和回调样式代码



我对这种承诺链接的工作原理感到困惑,我对承诺和 js 仍然相当陌生,所以请原谅我

第三行,return user.findOne({email}).then((user) => {,我只是对返回这个承诺如何做任何事情感到困惑,因为它在 .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()
}
});
});
});
}

在快速应用中使用的 findByCredentials 模型方法

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("!");
})

我刚刚创建的更简单的示例,这部分

return plus(1).then((res) => {

返回新的承诺((解析,拒绝) => { 是我难以理解的问题

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);
});

正如@Bergi在您的OP的评论中所说,真正的力量或Promises来自在其他Promisesthen中返回它们。

  • 这使您可以以干净的方式链接承诺。
  • 要链接承诺,您在链中的所有操作都必须是承诺。
  • 您的bcrypt.compare函数使用回调来表示它已完成,因此您需要将该函数转换为Promise

这很容易做到。只需将回调样式的代码包装在 Promise 中,并resolve回调的result,或者如果回调是用err调用的,则reject

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)
})
})   
}

。然后我们可以正确链接:

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
})
})
}

这里的关键是,您在.then()return的任何内容都将作为参数传递给下一个链接.then()

附加信息:

  • bcrypt.compare已经返回了一个Promise,所以我们可以避免将其包装成承诺的全部麻烦。我特意将它与回调一起使用,以说明您应该如何在 Promise 链中处理回调样式的代码。

最新更新