节点承诺链接导致函数中返回语句过多

假设下一个重置密码function:

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

这个函数的调用者期待一个承诺作为返回值。

但是我的问题是:这是链接承诺的正确方法吗?

它看起来像所有的返回语句使代码看起来不可读。

有没有办法避免这种情况? 有没有办法避免return Promise.resolve().then...在开始?

PS。 我正在使用bluebird作为promise lib

更新:

Dans回答之后,我做了以下工作:

 function login(email, password) { return User.findByMail(email).then(function(user){ return [user.comparePassword(password), user]; }) } 

而我不断地得到未定义不是一个函数,这里是堆栈跟踪:

 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) 

它看起来像所有的返回语句使代码看起来不可读。 有没有办法避免这种情况?

实际上有两种方式,但是没有一种可以在ES5中使用:

  • 如果只有一个expression式,箭头函数不需要显式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); ); 
  • asynchronous函数允许您完全闪避,并使用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提出的function,但你可以在你的编译器中使用它们。 对于Bluebird,您也可以使用生成器,请参阅Promise.coroutine文档 。

有没有办法避免返回Promise.resolve()。然后…在开始?

是。 你可以用第一个promise返回函数来启动你的链:

 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) { … 

当前解决scheme的差异(exception处理,asynchronous)是微不足道的。

User.findByMail(email)产生一个值而不是一个承诺时,以下情况不成立:

你可以很容易地删除第一个:

 return Promise.resolve().then(function() { return User.findByMail(email); }) 

是相同的:

 return User.findByMail(email) 

因为它不:

 return Promise.resolve(User.findByMail(email)) 

将把这个价值作为承诺来包装。

为了链接你不必链接:

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