【问题标题】:Understanding the execution order of subsequent then() handlers of an resolved promise了解已解决承诺的后续 then() 处理程序的执行顺序
【发布时间】:2017-06-06 22:00:00
【问题描述】:

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

但我不知道调用堆栈如何处理包含“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之前。那么当代码到达两个不同的“返回”时究竟发生了什么?

【问题讨论】:

  • 删除了 1.1.4 和 1.1.5 的回调 - 它们没有被引用,因此更不容易理解,每个人都已经明白了 1.1.2 的意义。没有他们,每个人仍然能够理解困境。
  • @try-catch-finally,感谢您的建议和编辑。我只是想让它更清楚,尽管有时会适得其反:)
  • 所以@try-catch-finally,我想知道您是否可以就我的问题提供建议?谢谢
  • 我试图将这个例子减少到最低限度,预测行为,测试它并逐步构建它。我不觉得 100% 有信心给你一个有用的答案。但我想说这是因为已经解决的 Promise 将同步调用其处理程序(即在其第一个处理程序中调用 p1.then() - 尽管最初是异步解析的,但现在剩余的处理程序将被称为同步)而Promise 总是被异步解析,因此在p1 中建立的堆栈有时间完成对处理程序的调用。一般建议:不要在p1.then() 内部p1.then() :/

标签: javascript callstack event-loop


【解决方案1】:

区别在http://promisesaplus.com/的promise解决过程中描述。

对于第一个返回值:

2.3.3.4 如果 then 不是一个函数,用 x 实现 promise。

第二个:

2.3.2 如果x是一个promise,采用它的状态[3.4]:

2.3.2.2 如果/当 x 被满足时,以相同的值履行承诺。

我们可以看到这个实现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;
}

当从then 函数返回一个promise 时,我们有两个独立的promise 对象:一个从传递给then 的函数返回,一个从then 返回。这些需要连接在一起,以便解决第一个问题,解决第二个问题。这是通过promise.then(deferred.resolve, ...)完成的

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

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

2.2.4 在执行上下文堆栈仅包含平台代码之前,不得调用 onFulfilled 或 onRejected。 [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

【讨论】:

  • 非常感谢您的文章非常清楚地说明了我想知道的内容!
猜你喜欢
  • 1970-01-01
  • 2023-03-05
  • 2020-08-14
  • 2020-02-12
  • 1970-01-01
  • 1970-01-01
  • 2020-02-05
  • 1970-01-01
  • 2022-01-22
相关资源
最近更新 更多