你可以避免与Promises完全嵌套吗?

4 javascript promise q bluebird

根据我的理解,Promises的主要卖点之一是能够编写扁平代码(或者比回调地狱更平坦).

虽然看起来在很多情况下我们需要嵌套promises,以便使用闭包.例如(来自q的文档,虽然我使用Bluebird):

function authenticate() {
    return getUsername()
        .then(function (username) {
            return getUser(username);
        })
        // chained because we will not need the user name in the next event
        .then(function (user) {
            return getPassword()
                // nested because we need both user and password next
                .then(function (password) {
                    if (user.passwordHash !== hash(password)) {
                        throw new Error("Can't authenticate");
                    }
                });
        });
}
Run Code Online (Sandbox Code Playgroud)

有没有更简洁的方法来做到这一点,没有嵌套?

编辑:我已经设法清理这个具体的例子使用.all,但有更复杂的情况,我不认为它可以做到:

function authenticate() {
    return Promise.all([
        getUsername().then(getUser),
        getPassword()
    ]).spread(function (user, password) {
        if (user.passwordHash !== hash(password)) {
            throw new Error('Can\'t authenticate');
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

Ben*_*aum 6

是的,你总是可以通过使用它们的代理的承诺来展平承诺链Promise.all(Promise.join在Bluebird中的简写).毕竟 - 承诺抽象值,您可以随时解开一个承诺,并让其他变量依赖它.

它是否更具可读性是另一个争论:

foo().then(function(a){
     return bar(a).then(function(b){
          return g(a,b); // "needed" to nest because I wanted `a`
     });
});
Run Code Online (Sandbox Code Playgroud)

可以写成:

var a = foo();
var b = a.then(bar);
Promise.join(a, b, function(a,b){
    return g(a, b); // alternatively, res could have been `Promise.join(a,b, g)`
});
Run Code Online (Sandbox Code Playgroud)

所以一般-你可以永远避免嵌套但很多时候你可能不想.

在您的情况下,这甚至可以是:

function authenticate() {
    var userPass = Promise.all([ getUsername().then(getUser), getPassword()]);
    var passHash = userPass.get(0).get("passwordHash");
    var newHash = userPass.get(1).then(hash);     
    var equal = Promise.join(userHash, newHash, function(a, b){ return a !==b });
    return equal.then(function(val){ if(!val) throw new Error("..."); });
}
Run Code Online (Sandbox Code Playgroud)

奉承?当然.更好?这是另一个问题.如果您有一个嵌套for循环,您可能希望将它保持为嵌套for循环并嵌套而不是破解该选项并使用单个循环.

  • 好东西,你的a,b,c例子正是我想要的.另外,我不喜欢使用.join,因为即使它节省了一些按键,但我觉得它的可读性较差(而且我很确定它不符合标准) (2认同)