2016-02-13 66 views
4

Asuming下一个复位密码功能:节点承诺,链接会导致功能太多return语句

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作为承诺的lib

UPDATE:

丹斯的回答后,我做了以下内容:

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) 
+0

您可以使用一个回调fonction –

+0

@JohnSmith你能否详细些吗? – tubu13

+0

对不起。我在我的手机上,但你可以尝试像这样 '忘记密码(电子邮件,(结果,错误)=> {if(err){...}; //做结果}} 然后 '函数forgotPassword(email,callback){return Promise.resolve(...)。then((resultResolve)=> {callback(resultResolve)})。catch((err)=> {callback(null,new Error(err) )}); }' –

回答

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提出的功能,但您已经可以在您的转译器中使用它们。使用蓝鸟,您也可以使用类似的发电机,请参阅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

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

你可以轻松地删除第一个为:

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

是一样的:

return User.findByMail(email) 

,因为它并不:

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

想包作为承诺的价值。

+0

你可以看看更新吗? – tubu13

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