关于promise:Promise理解看了又看

21次阅读

共计 2879 个字符,预计需要花费 8 分钟才能阅读完成。

Promise 哪些 API 波及了微工作?

Promise 中只有波及到状态变更后才须要被执行的回调才算是微工作,比如说 then、catch、finally,其余所有的代码执行都是宏工作(同步执行)。

上图中蓝色为同步执行,黄色为异步执行(丢到微工作队列中)。

这些微工作何时被退出微工作队列?

这个问题咱们依据 ecma 标准来看:

  • 如果此时 Promise 状态为 pending,那么胜利或失败的回调会别离被退出至 [[PromiseFulfillReactions]] 和 [[PromiseRejectReactions]] 中。如果你看过手写 Promise 的代码的话,应该能发现有两个数组存储这些回调函数。
  • 如果此时 Promise 状态为非 pending 时,回调会成为 Promise Jobs,也就是微工作。

同一个 then,不同的微工作执行

高级

Promise.resolve()
  .then(() => {console.log("then1");
    Promise.resolve().then(() => {console.log("then1-1");
    });
  })
  .then(() => {console.log("then2");
  });

尽管 then 是同步执行,并且状态也曾经变更。但这并不代表每次遇到 then 时咱们都须要把它的回调丢入微工作队列中,而是期待 then 的回调执行结束后再依据状况执行对应操作。

基于此,咱们能够得出第一个论断: 链式调用中,只有前一个 then 的回调执行结束后,跟着的 then 中的回调才会被退出至微工作队列。

中级

大家都晓得了 Promise resolve 后,跟着的 then 中的回调会马上进入微工作队列。

那么以下代码你认为的输入会是什么?

let p = Promise.resolve();

p.then(() => {console.log("then1");
  Promise.resolve().then(() => {console.log("then1-1");
  });
}).then(() => {console.log("then1-2");
});

p.then(() => {console.log("then2");
}); 

依照一开始的认知咱们不难得出 then2 会在 then1-1 后输入,然而理论状况却是相同的。

基于此咱们得出第二个论断: 每个链式调用的开始会首先顺次进入微工作队列。

接下来咱们换个写法:

let p = Promise.resolve().then(() => {console.log("then1");
  Promise.resolve().then(() => {console.log("then1-1");
  });
}).then(() => {console.log("then2");
});

p.then(() => {console.log("then3");
});


上述代码其实有个陷阱,then 每次都会返回一个新的 Promise,此时的 p 曾经不是 Promise.resolve() 生成的,而是最初一个 then 生成的,因而 then3 应该是在 then2 后打印进去的。

顺便咱们也能够把之前得出的论断优化为: 同一个 Promise 的每个链式调用的开始会首先顺次进入微工作队列。

高级

then1-2 会在何时打印进去?

Promise.resolve()
  .then(() => {console.log("then1");
    Promise.resolve()
      .then(() => {console.log("then1-1");
        return 1;
      })
      .then(() => {console.log("then1-2");
      });
  })
  .then(() => {console.log("then2");
  })
  .then(() => {console.log("then3");
  })
  .then(() => {console.log("then4");
  });

解析:

  • 第一次 resolve 后第一个 then 的回调进入微工作队列并执行,打印 then1
  • 第二次 resolve 后外部第一个 then 的回调进入微工作队列,此时内部第一个 then 的回调全副执行结束,须要将内部的第二个 then 回调也插入微工作队列。
  • 执行微工作,打印 then1-1 和 then2,而后别离再将之后 then 中的回调插入微工作队列
  • 执行微工作,打印 then1-2 和 then3,之后的内容就不一一阐明了

接下来咱们把 return 1 批改一下,后果可就大不相同啦:

Promise.resolve()
  .then(() => {console.log("then1");
    Promise.resolve()
      .then(() => {console.log("then1-1");
        return Promise.resolve();})
      .then(() => {console.log("then1-2");
      });
  })
  .then(() => {console.log("then2");
  })
  .then(() => {console.log("then3");
  })
  .then(() => {console.log("then4");
  });

当咱们 return Promise.resolve() 时,你猜猜 then1-2 会何时打印了?

答案是最初一个才被打印进去。

为什么在 then 中别离 return 不同的货色,微工作的执行程序竟有如此大的变动?以下是笔者的解析。

PS:then 返回一个新的 Promise,并且会用这个 Promise 去 resolve 返回值,这个概念须要大家先理解一下。

依据 Promise A+ 标准

依据标准 2.3.2,如果 resolve 了一个 Promise,须要为其加上一个 then 并 resolve。

if (x instanceof MyPromise) {if (x.currentState === PENDING) { } else {x.then(resolve, reject);
  }
  return;
}

上述代码节选自手写 Promise 实现。

那么依据 A+ 标准来说,如果咱们在 then 中返回了 Promise.resolve 的话会多入队一次微工作,然而这个论断还是与理论不符的,因而咱们还须要寻找其余权威的文档。

依据 ECMA – 262 标准

依据标准 25.6.1.3.2,当 Promise resolve 了一个 Promise 时,会产生一个 NewPromiseResolveThenableJob,这是属于 Promise Jobs 中的一种,也就是微工作。

This Job uses the supplied thenable and its then method to resolve the given promise. This process must take place as a Job to ensure that the evaluation of the then method occurs after evaluation of any surrounding code has completed.

并且该 Jobs 还会调用一次 then 函数来 resolve Promise,这也就又生成了一次微工作。

这就是为什么会触发两次微工作的起源。

正文完
 0