节点承诺链接导致函数中返回语句过多
假设下一个重置密码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); }) }); }