Javascript 承诺输出因节点和浏览器而异

Javascript 承诺输出因节点和浏览器而异,javascript,node.js,google-chrome,promise,Javascript,Node.js,Google Chrome,Promise,以下代码块在节点和浏览器之间的执行方式不同。当然,存在不同的环境、不同的处理时间和竞争条件的可能性。但根据我对承诺的理解,这段代码应该在不同的环境中保持一致 我期待Chrome/浏览器的结果。我不期望NodeJs的结果。我不明白为什么每个newPromise的然后链在masterPromise的然后链继续之前没有完成。换句话说,因为一个新的承诺在一个thenfn中返回给masterPromise承诺链,我希望新承诺的then链在masterPromise承诺链恢复之前完成 我希望有人能在下面的实

以下代码块在节点和浏览器之间的执行方式不同。当然,存在不同的环境、不同的处理时间和竞争条件的可能性。但根据我对承诺的理解,这段代码应该在不同的环境中保持一致

我期待Chrome/浏览器的结果。我不期望NodeJs的结果。我不明白为什么每个
newPromise
然后
链在
masterPromise
然后
链继续之前没有完成。换句话说,因为一个新的承诺在一个then
fn
中返回给
masterPromise
承诺链,我希望新承诺的then链在masterPromise承诺链恢复之前完成

我希望有人能在下面的实现中戳一个洞,并解释为什么NodeJs结果是有效的

使用chrome 44和node 12.6

例:

节点:

铬:

registered 1
registered 1 (verbatim, syncronous echo)
registered 2
registered 2 (verbatim, syncronous echo)
registered 3
registered 3 (verbatim, syncronous echo)
我不明白为什么每一条新的承诺链都没有在下定决心后立即执行

然后回调不会立即调用

var resolve;
new Promise(function (r) { resolve = r; })
    .then(function () { console.log(2); });
resolve();
console.log(1);
日志:

承诺解析的行为类似于零延迟的
setTimeout

更新:

-----------+------------
wait       |  resolved
-----------+------------
timeout1   |             initial state
timeout2   |
-----------+------------
           | timeout1    after 100 ms
timeout2   |
-----------+------------
           | resolve1    then Chrome variant
           | timeout2
-----------+------------
           | timeout2    or Node variant
           | resolve1
-----------+------------
setTimeout
的比较不太正确,因为存在以下限制: 类似之处在于异步承诺

更新2:

-----------+------------
wait       |  resolved
-----------+------------
timeout1   |             initial state
timeout2   |
-----------+------------
           | timeout1    after 100 ms
timeout2   |
-----------+------------
           | resolve1    then Chrome variant
           | timeout2
-----------+------------
           | timeout2    or Node variant
           | resolve1
-----------+------------
两种变体都符合规范。Chrome队列似乎在后续超时回调之前解析回调

我不明白为什么每个
newPromise
链都不是
在
masterPromise
链继续之前完成。一个新的
承诺返回到
masterPromise
Promise链中,然后 fn
,那么它不应该在主承诺之前等待吗 承诺链恢复

不。看来你的误解是关于“万事达承诺链”:根本没有这样的事情。
您有一个
masterPromise
,然后您链接了三个不同的
,然后从中调用了
。当
masterPromise
解析时(立即),它会看到3次回调,并按注册顺序调用所有回调。它不关心这些回调做什么,不管它们是否异步,也不等待它们的承诺结果。在您的案例中,所有这些子链都创建承诺,并通过它们推进其子链,但这3个子链彼此完全独立

也许通过更具描述性的日志记录充实您的代码有助于理解您在做什么:

function delay(number) {
    console.log("creating promise for", number);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log('resolving promise with', number);
            resolve(number);
        }, 100);
    });
};
function result(n) {
    console.log("received", number);
}

var masterPromise = Promise.resolve();

masterPromise.then(function(){ delay(1).then(result); }); // chain 1
masterPromise.then(function(){ delay(2).then(result); }); // chain 2
masterPromise.then(function(){ delay(3).then(result); }); // chain 3
console.log("created chains");
你在这里看到的日志是

// .then chain 1    -------,
// .then chain 2    ------- \ -,
// .then chain 3    -------- \ -\ -,
created chains                |  |  |
                              |  |  | 3 then callbacks in the order they were registered
creating promise for 1      <´   |  |
// setTimeout 100   -----,       |  |
                          \     /   |
creating promise for 2     | <-´    |
// setTimeout 100   ------ |-,      /
                           |  \    /
creating promise for 3     |  | <-´
// setTimeout 100   ------ |- |-,
                           |  |  \
…                          |  |  | 3 timeout callbacks in the order they were scheduled
                           |  |  |
resolving promise with 1 <´   |  |
// resolve()                  |  |
[…]                           /  |
resolving promise with 2  <-´    |
// resolve()                     /
[…]                             /
resolving promise with 3   <---´
// resolve()
[…]
//。然后链1--------,
//.然后链2---------------,
//.然后链3---------------\-,
创建链| ||
|| | 3然后按注册顺序回调

为1创造承诺你需要详细说明为什么“基于你对承诺的理解”,一种或另一种行为应该是预期的。我认为这是不确定的,根据相关规范,这两种模式中的任何一种都是有效的行为。@Pointy,fair!Updated@Pointy,我再次更新以获得更窄的焦点。是什么在句法上导致了不确定性,你看到了吗?一位同事看到这个问题,认为它也应该是确定性的。然而,他也遇到了和我一样的问题,尽管他用一把小提琴演示了这个问题!这不是语法问题,而是语义问题。我完全看不出它有什么决定性的原因。不同的事件组彼此之间没有依赖关系,因此调用顺序应该完全没有区别。是的,这就是我认为运行时可以生成任意一个结果并且是正确的原因。尽管有人可能会认为,
.then()
只要承诺已经解决,就会直接进行函数调用,但这不是它应该工作的方式:回调应该使用干净的堆栈运行,因此它是通过某种机制调用的,本质上就像这个答案所描述的那样。因此,浏览器可能会在挂起的超时之前处理,也可能不会。(这是我的观点,但这个答案仍然正确。)耶,这对我来说是个新闻。谢谢。很高兴知道这是下一次可能的行动。但它仍然没有解释以下内容,这与预期背道而驰“新承诺”在“主承诺”的其中一个内返回。在masterPromise的then链继续之前,newPromise的then不是都应该执行吗?我觉得这份合同没有得到履行。@cdaringe没有-为什么会发生这种情况?嘿@Pointy,我相信是因为这个。对吗?如果X有一个thenable,并且该thenable返回一个承诺Y,那么承诺链将适应Y的状态,并且应该解析出Y的then链。假设Y的thenables返回一个承诺Z。在这种情况下,Z应该实现,然后是任意的Y thens,最后是X上剩下的任何东西@这可能很重要,但我不确定的是“then”回调的调用应该如何与异步环境的其余部分相关。
function delay(number) {
    console.log("creating promise for", number);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log('resolving promise with', number);
            resolve(number);
        }, 100);
    });
};
function result(n) {
    console.log("received", number);
}

var masterPromise = Promise.resolve();

masterPromise.then(function(){ delay(1).then(result); }); // chain 1
masterPromise.then(function(){ delay(2).then(result); }); // chain 2
masterPromise.then(function(){ delay(3).then(result); }); // chain 3
console.log("created chains");
// .then chain 1    -------,
// .then chain 2    ------- \ -,
// .then chain 3    -------- \ -\ -,
created chains                |  |  |
                              |  |  | 3 then callbacks in the order they were registered
creating promise for 1      <´   |  |
// setTimeout 100   -----,       |  |
                          \     /   |
creating promise for 2     | <-´    |
// setTimeout 100   ------ |-,      /
                           |  \    /
creating promise for 3     |  | <-´
// setTimeout 100   ------ |- |-,
                           |  |  \
…                          |  |  | 3 timeout callbacks in the order they were scheduled
                           |  |  |
resolving promise with 1 <´   |  |
// resolve()                  |  |
[…]                           /  |
resolving promise with 2  <-´    |
// resolve()                     /
[…]                             /
resolving promise with 3   <---´
// resolve()
[…]