为什么Promise.all(数组)没有立即解决?

时间:2016-03-19 08:01:42

标签: javascript node.js promise settimeout es6-promise

我在我的机器上运行代码示例(安装了Node 5.8.0)并获得下一个结果(请参阅代码示例之后)。

代码示例:

'use strict'

var p1 = Promise.resolve();
var p2 = Promise.resolve();

var p12 = Promise.all([p1, p2]);

var cb = function() {
  console.log(p12);
}

setTimeout(cb, 0);

console.log(p1);
console.log(p2);
console.log(p12);

结果:

承诺{undefined}
承诺{undefined}
承诺{<pending>}
承诺{[undefined,undefined]}

为什么在p1和p2之后不能立即解析p12(在程序开始时解析p1和p1),为什么“timeouted”p12得到解决? 是否需要一些时间来Promise.all(数组)得到解决?

1 个答案:

答案 0 :(得分:4)

根据promise规范,在事件循环完成当前循环后,始终异步调用promise履行或拒绝处理程序。因此,p12不会立即解决,即使它的参数都是已解决的承诺。因此,直到此事件循环结束后不久,它才会得到解决。这就解释了为什么你的第一个陈述:

console.log(p12);

表明承诺仍然是&#34;等待&#34;。它尚未被调用当前的.then()处理程序(如果有的话)。但是,一旦当前的代码线程完成执行并且控制返回到事件队列中的下一个事件,那么随后将解析该承诺,从而setTimeout()将其视为已解决。

这是出于调用者一致性原因而完成的,因此无论promise已经解决还是尚未解决,都会以异步方式一致地调用.then()个处理程序。这允许调用代码始终一致地编码,而不必担心承诺是否已经解决。在所有情况下,在当前堆栈展开并完成后调用.then()个处理程序。

来自Promises/A+ specification

  在执行之前,不得调用onPulfilled或onRejected   上下文堆栈仅包含平台代码。

     

这里的“平台代码”意味着引擎,环境和承诺   实施代码。在实践中,这个要求确保了这一点   在事件发生后,onFulfilled和onRejected异步执行   循环转入然后调用,并使用新堆栈。这可以   使用“宏任务”机制(如setTimeout或)实现   setImmediate,或者使用“微任务”机制   MutationObserver或process.nextTick。自承诺实施以来   被认为是平台代码,它本身可能包含任务调度   队列或“trampoline”,其中调用处理程序。

因此,所有这一切的结果是承诺总是在当前执行线程完成后异步解析。虽然内部细节可能比这更复杂(可能涉及微任务),但您可以通过在事件队列中发布消息来逻辑地考虑通过现在正在等待解析/拒绝的消息来解决。而且,每当事件队列完成当前正在运行的内容并转而运行promises .then()处理程序时,它们才会执行。