假设下一个重置密码功能:
function forgotPassword(email){
return Promise.resolve().then(function() {
return User.findByMail(email);
}).then(function(user){
if (!user) {
return Promise.reject({message: 'Cannot find user with that email'});
}
return [user, tokensService.createRandomBytes()];
}).spread(function(user, token){
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
return [user.saveAsync(), token];
}).spread(function(user, token){
return emailService.sendResetPassword(user.email, token);
});
}
此函数的调用者期望将promise作为返回值。
但我的问题是: 这是连锁承诺的正确方法吗?
在我看来,所有返回语句都会使代码看起来不可读。
有没有办法避免这种情况?有没有办法在开始时避免return Promise.resolve().then...
?
PS。我使用bluebird
作为承诺lib
更新:
在Dans回答后,我做了以下事情:
function login(email, password) {
return User.findByMail(email).then(function(user){
return [user.comparePassword(password), user];
})
}
我一直得到Undefined不是一个函数,这里是堆栈跟踪:
TypeError: undefined is not a function
at Object.login (/home/royi/projects/travessey-api/src/authentication/authentication-controller.js:17:11)
at /home/royi/projects/travessey-api/src/authentication/authentication-router.js:8:18
at Layer.handle [as handle_request] (/home/royi/projects/travessey-api/node_modules/express/lib/router/layer.js:95:5)
at next (/home/royi/projects/travessey-api/node_modules/express/lib/router/route.js:131:13)
at Route.dispatch (/home/royi/projects/travessey-api/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/home/royi/projects/travessey-api/node_modules/express/lib/router/layer.js:95:5)
at /home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:277:22
at Function.process_params (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:330:12)
at next (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:271:10)
at Function.handle (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:176:3)
at router (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:46:12)
at Layer.handle [as handle_request] (/home/royi/projects/travessey-api/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:312:13)
at /home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:280:7
at Function.process_params (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:330:12)
at next (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:271:10)
at allowCrossDomains (/home/royi/projects/travessey-api/src/authentication/authentication-middleware.js:34:5)
at Layer.handle [as handle_request] (/home/royi/projects/travessey-api/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:312:13)
at /home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:280:7
at Function.process_params (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:330:12)
at next (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:271:10)
at /home/royi/projects/travessey-api/node_modules/express-validator/lib/express_validator.js:228:5
at Layer.handle [as handle_request] (/home/royi/projects/travessey-api/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:312:13)
at /home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:280:7
at Function.process_params (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:330:12)
at next (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:271:10)
at urlencodedParser (/home/royi/projects/travessey-api/node_modules/body-parser/lib/types/urlencoded.js:81:44)
at Layer.handle [as handle_request] (/home/royi/projects/travessey-api/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:312:13)
at /home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:280:7
at Function.process_params (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:330:12)
at next (/home/royi/projects/travessey-api/node_modules/express/lib/router/index.js:271:10)
答案 0 :(得分:2)
在我看来,所有的返回语句都会使代码看起来不可读。有没有办法避免这种情况?
实际上有两种方式,但它们都不适用于ES5:
如果您只有一个表达式,则箭头函数不需要显式return
:
const forgotPassword = (email) =>
Promise.resolve().then(() =>
User.findByMail(email)
).then(user =>
user
? [user, tokensService.createRandomBytes()]
: Promise.reject({message: 'Cannot find user with that email'})
).spread((user, token) => {
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
return [user.saveAsync(), token];
}).spread((user, token) =>
emailService.sendResetPassword(user.email, token);
);
异步功能允许您完全躲避then
并使用await
关键字简化所有内容:
async function forgotPassword(email) {
await Promise.resolve();
let user = await User.findByMail(email);
if (!user)
throw new Error('Cannot find user with that email');
let token = tokensService.createRandomBytes();
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user = await user.saveAsync();
return emailService.sendResetPassword(user.email, token);
}
它们是ES8提议的功能,但您已经可以在浏览器中使用它们了。使用Bluebird,您也可以类似地使用生成器,请参阅Promise.coroutine
docs。
有没有办法避免返回Promise.resolve()。然后......一开始?
是。您可以使用第一个承诺返回功能启动您的链:
function forgotPassword(email){
return User.findByMail(email).then(function(user){
if (!user) {
…
如果您不确定是否返回承诺,您也可以使用
function forgotPassword(email){
return Promise.resolve(User.findByMail(email)).then(function(user){
if (!user) {
…
当前解决方案的差异(异常处理,异步)非常小。
答案 1 :(得分:1)
当User.findByMail(email)
导致值而非承诺时,以下情况不属实:
您可以轻松删除第一个:
return Promise.resolve().then(function() { return User.findByMail(email); })
与:
相同return User.findByMail(email)
因为它没有:
return Promise.resolve(User.findByMail(email))
将该值包装为承诺。
答案 2 :(得分:0)
你不必为了链接而链:
function forgotPassword(email) {
return Promise.all([
User.findByMail(email),
// creating an unrelated random token doesn't have to be done later
tokensService.createRandomBytes()
]).spread(function(user, token) {
if (!user) {
// equivalent to your Promise.reject() but cleaner
// and err.message == 'Cannot find user with that email'
throw new Error('Cannot find user with that email');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
// nothing wrong with one level of nesting
return user.save().then(function(usr) {
return emailService.sendResetPassword(user.email, token);
})
});
}