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

て烟熏妆下的殇ゞ 提交于 2019-11-30 04:37:13

问题


I am learning Promise, in order to understand it I read a bit about Event loop of JavaScript. This article briefly introduced the working of event loop such as call stack, event table and message queue.

But I don't know how the call stack deal with the line containing 'return', and what happens thereafter. Below is an example that I wrote to hopefully understand how Promise works based on event loop. Also see http://jsbin.com/puqogulani/edit?js,console if you want to give it a go.

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");

As can be seen, there are two "return", using each of them will give a different output order. Specifically, when using return 30;, 1.1.2, 1.1.3 are after 15, but when using return new Promise(...), 1.1.2, 1.1.3 are before 15. So what exactly happened when the code reached two different 'return'?


回答1:


The difference is described in http://promisesaplus.com/ under the promise resolution procedure.

For the first return value:

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

For the second:

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.

We can see this implemented q.js. This is one possible implementation but seems to explain the delay:

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;
}

When returning a promise from the then function, we have two separate promise objects: the one returned from the function passed to then, and the one returned from then. These need to be connected together so that resolving the first, resolves the second. This is done with promise.then(deferred.resolve, ...)

The first delay comes from Q.nextTick. This executes the function on the next iteration of the event loop. There's some discussion in the commit comments on why it's needed.

Calling promise.then adds a further delay of one iteration of the event loop. As required in the spec:

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

The execution would go something like:

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


来源:https://stackoverflow.com/questions/41788626/understanding-the-execution-order-of-subsequent-then-handlers-of-an-resolved-p

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!