作业队列如何与 Promise 一起工作?

wew*_*ewq 4 javascript promise

我正在学习 JS 中的 Promise,并对 Promise 如何在幕后与作业队列一起工作感到好奇。为了解释我的困惑,我想向您展示这段代码:

new Promise(function(resolve, reject) {

  setTimeout(() => resolve(1), 1000);

}).then(function(result) {

  alert(result); // 1

  return new Promise((resolve, reject) => { // (*)
    setTimeout(() => resolve(result * 2), 1000);
  });

})
Run Code Online (Sandbox Code Playgroud)

如果你看上面的代码,是不是then()的回调被提前放入Job队列等待promise解析呢?或者,只有在 Promise 得到解决后,then() 的回调才会被推入作业队列吗?

T.J*_*der 6

当需要调用 Promise 回调时,作业根本不会进入标准作业队列 (ScriptJobs);它进入 PromiseJobs 队列。PromiseJobs 队列将被处理,直到 ScriptJobs 队列中的每个作业结束时队列为空。(规范中的更多内容:作业和作业队列。)

我不确定您期望从代码中得到什么输出,因为您没有说,但让我们举一个更简单的例子:

console.log("top");
new Promise(resolve => {
    setTimeout(() => {
        console.log("timer callback");
    }, 0);
    resolve();
})
.then(() => {
    console.log("then callback 1");
})
.then(() => {
    console.log("then callback 2");
});
console.log("bottom");
Run Code Online (Sandbox Code Playgroud)

可靠地,其输出为:

顶部
底部
然后回调1
然后回调2
定时器回调

因为:

  1. 运行该脚本的 ScriptJobs 作业将运行
  2. console.log("top")运行
  3. Promise 执行器函数代码运行,其中
    • 为“现在”安排一个计时器作业,该作业将立即或几乎立即进入 ScriptJobs 队列
    • 通过不带参数调用(这实际上就像用 调用then它一样,不可用会触发承诺的履行)来履行承诺(这意味着承诺在调用之前已解决)resolveundefined
  4. 第一个then连接第一个履行处理程序,对 PromiseJobs 作业进行排队,因为承诺已经履行
  5. 第二个then连接第二个履行处理程序(不将作业排队,等待第一个处理程序的承诺then
  6. console.log("bottom")运行
  7. 当前 ScriptJob 作业结束
  8. 引擎处理正在等待的 PromiseJobs 作业(第一个履行处理程序)
  9. 输出"then callback 1"并履行第一个的then承诺(通过返回)
  10. 将另一个作业放入 PromiseJobs 队列中,以便回调到第二个履行处理程序
  11. 由于 PromiseJobs 队列不为空,因此会选取并运行下一个 PromiseJob
  12. 第二个履行处理程序输出"then callback 2"
  13. PromsieJobs 为空,因此引擎拾取下一个 ScriptJob
  14. 该 ScriptJob 处理计时器回调并输出"timer callback"

在 HTML 规范中,他们使用略有不同的术语:“任务”(或“宏任务”)用于 ScriptJobs 作业,“微任务”用于 PromiseJobs 作业(以及其他类似作业)。

关键点是:在 ScriptJob 期间排队的所有 PromiseJobs 都会在该 ScriptJob 完成时得到处理,其中包括它们排队的任何 PromiseJobs;只有当 PromiseJobs 为空时,才会运行下一个 ScriptJob。