链式 Q Promise 序列不起作用

Chained Q Promise sequence wont work

Node.js 应用 Q Promise 中,我有这段代码,我想看到这个结果:

a
b
end

但我看到了这个:

end
a
b

这是我的代码:

var a =  function(){
        return q.Promise(function(resolve, reject){
            resolve("a");
        });
    };

    var b =  function(){
        return q.Promise(function(resolve, reject){
            resolve("b");
        });
    };

    var c =  function(){
        return q.Promise(function(resolve, reject){
            resolve("c");
        });
    };

    var master =  q();

    master.then(function(){
        return a();
    })

    .then(function(res){
        console.error(res);
        return b();
    })

    .then(function(res){
        console.error(res);
            return c();
    });

    master.then(function(){
        console.error("end");
    });

如果我更改此部分:

master.then(function(){
        return a();
    })

对此:

master = master.then(function(){
        return a();
    })

代码工作正常,但我不知道为什么?了解和理解这一点对我来说很重要。有人可以给我解释一下吗?

您看到的是链接和分支之间的区别,它们是承诺控制流的不同形式。

当你这样做时:

master.then(function(){
    return a();
})

然后,然后:

master.then(function(){
    console.error("end");
});

您已将两个 .then() 处理程序挂接到同一个承诺。这是分支。当 master() 被解析时,这些 .then() 处理程序中的每一个都将彼此独立地调用,并且每个都成为自己的独立链(因此原始链被 分支 为两条链)。

链接就像:

master.then(function(){
    return a();
}).then(function(){
    console.error("end");
});

在链接的情况下,第二个 .then() 处理程序将不会被调用,直到 a() 返回的任何承诺也被解决并且如果 a() 抛出或 returns a拒绝承诺这里的第二个 .then() 处理程序根本不会被调用。

在第一个示例的分支情况下,第二个 .then() 处理程序在第一个 .then() 处理程序之后立即被调用,而不管 a() returns.

当你这样做时:

master = master.then(function(){
    return a();
})

在你做之前:

master.then(function(){
    console.error("end");
});

您正在手动链接它们,以便有效地完成:

master.then(function(){
    return a();
}).then(function(){
    console.error("end");
});

请记住,每次调用 .then() returns 都是一个新的承诺。链接,如:

a().then(b).then(c)

在链中的每个步骤创建一个新的新承诺,并且在处理程序 returns 也被解决之前,新的承诺不会被解决。

所以,当你在做的时候:

master = master.then(function(){
    return a();
})

您正在抓住那个中间承诺(通过分配给 master)并坚持下去,这样您就可以将一些东西链接到它上面。如果你这样做:

master.then(function(){
    return a();
})

然后,从 master.then() 返回的承诺已经完成,不能直接链接到。


有关链接与分支的进一步描述,请参阅这些帖子:


这是一个显示 promise 分支的片段:

function log(str) {
    var d = document.createElement("div");
    d.textContent = str;
    document.body.appendChild(d);
}

function setDelay(t, msg) {
    return function() {
        return delay(t, msg);
    }
}

function delay(t, msg) {
    // if only one string argument, default t to 500ms
    if (typeof t === "string" && typeof msg === "undefined") {
        msg = t;
        t = 500;
    }
    return new Promise(function(resolve) {
        setTimeout(function() {
            log(msg);
            resolve(msg);
        }, t);
    });
}

var x = Promise.resolve().then(setDelay("One"))
 .then(setDelay("Two"))
 .then(function() {
     log("Three");
 });

x.then(setDelay(500, "Four"))
    .then(setDelay(500, "Five"))
    .then(setDelay(500, "Six"));

x.then(setDelay(50, "Seven"))
    .then(setDelay(50, "Eight"))
    .then(setDelay(50, "Nine"));

x.then(setDelay(10, "Ten"))
    .then(setDelay(10, "Eleven"));

说明

一、二、三链接在一起,所有分支都依赖于它们。然后,这条链分裂成三个独立的分支。

十、十一分支首先执行,因为它有 10 毫秒计时器。

然后,接下来是七、八、九分支,定时器为 50 毫秒。

然后,四、五、六分支以 500 毫秒计时器结束

注意:我故意这样做是为了让分支计时器不重叠,但这不是承诺强制执行的事情,由于我选择的计时器值,这里恰好是这种情况。所有三个分支都是 运行 独立的,如果它们的活动时间重叠,则可以交错。