如何简化深层嵌套的承诺

时间:2015-08-19 15:43:44

标签: javascript promise ecmascript-6 bluebird es6-promise

我遇到过一种情况,我需要在then()中的每个“else”子句中断,这看起来不比嵌套回调更好,这是一个登录过程:

User.findOne({
    username: username
}).exec()
    .then(user => {
        if (user) {
            return user.verifyPassAsync()
                .then(matched => {
                    if (matched) {
                        return User.getBriefProfile(username))
                            .then(emp => {
                                if (emp) {
                                    return saveToSession(emp);
                                } else {
                                    //return 
                                }})
                    } else {
                        //return ...
                    }})
        } else {
        // return false
        }
    })

有什么方法可以简化这个吗?

1 个答案:

答案 0 :(得分:2)

不是真的,因为你不是(仅)在这里筑巢,而是条件。如果使用async / await(ES7)编写,则您的函数看起来像

var user = await User.findOne({username}).exec();
if (user) {
    var matched = await user.verifyPassAsync();
    if (matched) {
        var emp = await User.getBriefProfile(username);
        if (emp) {
            return saveToSession(emp);
        } else {
            // return …;
        }
    } else {
        // return …;
    }
} else {
    // return …;
}

如您所见,嵌套是您的程序所固有的。虽然它已经有点简化了(then调用没有嵌套),你现在可以使用Promise.coroutine和ES6生成器来实现这一点。

您最好的选择可能是throw每个else出现错误,并将链变为线性,最后.catch。当然,如果你在每个else块中做同样的事情,那么你也可以写

var user = await User.findOne({username}).exec();
if (user)
    var matched = await user.verifyPassAsync();
if (matched)
    var emp = await User.getBriefProfile(username);
if (emp) {
    return saveToSession(emp);
else
    // return …;

可以轻松转换回then回调:

User.findOne({username: username}).exec()
.then(user =>
    user && user.verifyPassAsync()
).then(matched =>
    matched && User.getBriefProfile(username);
).then(emp =>
    emp ? saveToSession(emp) : …;
);