javascript - 如何预测跨 Promise.then 链的微任务顺序?

标签 javascript promise es6-promise event-loop

确定这段代码输出的 JavaScript 规则是什么?:

Promise.resolve()
    .then(() => console.log("Microtask 1"))
    .then(() => console.log("Microtask 11"));

Promise.resolve()
    .then(() => console.log("Microtask 2"))
    .then(() => console.log("Microtask 22"))

这是输出:

Microtask 1
Microtask 2
Microtask 11
Microtask 22

但为什么这不是输出?:

Microtask 1
Microtask 11
Microtask 2
Microtask 22

最佳答案

你看到你看到的输出是因为 Microtask 11 的微任务没有排队直到 Microtask 1 的微任务运行,此时 的微任务微任务 2 已经在队列中等待。所以顺序是(跳过一些细节;更多内容见下文):

  1. 微任务 1 的队列微任务
  2. 微任务 2 的队列微任务
  3. 任务完成,开始处理微任务:
    1. 执行 #1 中排队的微任务
      • 输出微任务1
      • 微任务 11 的队列微任务
    2. 执行 #2 中排队的微任务
      • 输出微任务2
      • Microtask 21的队列微任务
    3. 执行 #3.1 中排队的微任务
      • 输出 微任务 11
    4. 执行 #3.2 中排队的微任务
      • 输出 微任务 21

因此,

Microtask 1
Microtask 2
Microtask 11
Microtask 21

But: Writing code that relies on the order of execution of disconnected promise chains / microtask sequences is asking for trouble. :-) You can only reason about it in relation to promises you know are already settled, and of course in the normal case, you don't know when (or even if) a promise will settle. Instead, if you need a specific order, connect the chains to ensure order.


Re skipped details: I sort of glossed over things in the main explanation to keep it short and clear, but for accuracy, let's look at:

Promise.resolve()
    .then(() => console.log("Microtask 1"))
    .then(() => console.log("Microtask 11"));

...就其本身而言,忽略第二个 promise 链以保持简单。

下面是该代码的执行方式(我的 blog post on promise 术语可能对阅读以下内容有所帮助):

  1. 执行 Promise.resolve(),创建一个 在这种特殊情况下 由值 undefined 实现的 promise 。
  2. 执行 .then(() => console.log("Microtask 1")),创建一个新函数并根据 Step 的 promise 调用 then 1. 这将创建并返回一个新的 promise ,并且在这种特殊情况下,排队一个微任务来调用该函数,因为 promise 已经实现。
  3. 执行 .then(() => console.log("Microtask 11")),创建一个新函数并根据 Step 的 promise 调用 then 2. 这将创建并返回一个新的 promise (我们在该代码中将其丢弃),并且由于步骤 2 中的 promise 仍处于待定状态,因此将函数作为履行处理程序添加到其中。
  4. 运行此代码的任务结束,因此 JavaScript 引擎处理微任务队列:
    1. 执行队列中的第一个微任务:
      1. 调用函数记录 Microtask 1
      2. 因为函数返回undefined,这不是一个 promise 或其他thenable ,引擎使用 undefined 实现步骤 2 中的 promise 。(如果函数返回了 promise 或其他 thenable,则该 promise 将解析为返回的 promise .)
        • 将微任务排队以调用在第 3 步中注册到该 promise 上的履行处理程序,该处理程序将在调用时记录 Microtask 11
    2. 执行队列中的下一个微任务(记住我们忽略了这个描述中的另一个 promise 链,所以在这种情况下下一个微任务是记录 Microtask 11 的那个刚刚添加到队列中,而不是记录 Microtask 2) 的那个:
      1. 调用函数记录 Microtask 11
      2. 由于该函数返回 undefined,这不是 promise 或其他 thenable,因此引擎使用 undefined 实现步骤 3 中的 promise 。
        • 这不会执行任何操作,因为该 promise 上没有注册任何履行处理程序。

关于javascript - 如何预测跨 Promise.then 链的微任务顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73797791/

相关文章:

javascript - 浏览器的 'Back' 按钮转到倒数第二页。为什么?

javascript - 如何在 Perl 网络爬虫中处理 Javascript?

javascript - promise 中的两次递归调用失败

javascript - 使用 transition.end() promise 链接转换

Javascript 类在 console.log 中返回不同的值

javascript - 如何在 fabric.js 中获取目标元素的属性值

javascript - 为 Jquery 的 slider handle 应用新的背景颜色

javascript - Promise 和 Deferred 在 jquery 中不起作用

javascript - Ember 过渡和渲染完成事件

javascript - 取消 ES6 promise