了解已解决承诺的后续 then() 处理程序的执行顺序

Understanding the execution order of subsequent then() handlers of an resolved promise

我正在学习 Promise,为了理解它,我阅读了一些关于 JavaScript 的事件循环的内容。这篇article简单介绍了调用栈、事件table、消息队列等事件循环的工作原理

但我不知道调用堆栈如何处理包含'return'的行,以及此后会发生什么。 下面是我写的一个例子,希望能理解 Promise 是如何基于事件循环工作的。如果您想尝试一下,另请参阅 http://jsbin.com/puqogulani/edit?js,console

var p1 = new Promise(
  function(resolve, reject){
    resolve(0);
});

p1.then(function(val){
  console.log(val);
  p1.then(function(){
    console.log("1.1.1");
    p1.then(function(){
      console.log("1.1.2");
      p1.then(function(){
        console.log("1.1.3");
      });
    });
  });

  p1.then(function(){
    console.log("1.2");
  })

  return 30;

  //return new Promise(function(resolve, reject){
  //  resolve(30);
  //});

})
  .then(function(val){
  console.log(val/2);
});

p1.then(function(){
  console.log("2.1");
});

console.log("Start");

可以看出,有两个"return",使用每一个都会给出不同的输出顺序。具体来说,使用return 30;时,1.1.2, 1.1.315之后,而使用return new Promise(...)时,1.1.2, 1.1.315之前。那么当代码到达两个不同的 'return' 时到底发生了什么?

区别在 http://promisesaplus.com/ 承诺解决程序下进行了描述。

对于第一个 return 值:

2.3.3.4 If then is not a function, fulfill promise with x.

第二个:

2.3.2 If x is a promise, adopt its state [3.4]:

2.3.2.2 If/when x is fulfilled, fulfill promise with the same value.

我们可以看到它已实现 q.js。这是一种可能的实现方式,但似乎可以解释延迟:

function coerce(promise) {
    var deferred = defer();
    Q.nextTick(function () {
        try {
            promise.then(deferred.resolve, deferred.reject, deferred.notify);
        } catch (exception) {
            deferred.reject(exception);
        }
    });
    return deferred.promise;
}

当 return 从 then 函数中获取一个承诺时,我们有两个单独的承诺对象:一个 return 从传递给 then 的函数中获取,以及return 编辑自 then。这些需要连接在一起,以便解决第一个问题,解决第二个问题。这是通过 promise.then(deferred.resolve, ...)

完成的

第一个延迟来自Q.nextTick。这将在事件循环的下一次迭代中执行该函数。 commit comments 中有一些关于为什么需要它的讨论。

调用promise.then 会进一步延迟事件循环的一次迭代。根据规范要求:

2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].

执行过程如下:

p1.then with function containing 1.1.1 is called
    function containing 1.1.1 is queued
p1.then with function containing 1.2 is called
    function containing 1.2 is queued
Promise resolving to 30 is returned
    Q.nextTick function is queued
----------
1.1.1 is printed
p1.then with function containing 1.1.2 is called
    function containing 1.1.2 is queued
1.2 is printed
Q.nextTick function is executed
    promise.then(deferred.resolve, ...) is queued
----------
1.1.2 is printed
p1.then with function containing 1.1.3 is called
    function containing 1.1.3 is queued
promise.then(deferred.resolve, ...) is executed
    function containing val/2 is queued
----------
1.1.3 is printed
val/2 is printed