Promise `.then`、`.catch` 和 `.finally` 如何以及何时进入事件循环微任务队列?

How and when Promise `.then`, `.catch` and `.finally` land in EventLoop micro-tasks queue?

.then.catch.finally 是在注册后立即进入 JS 事件循环(当 JS 运行时解释适当的代码时)还是以某种方式不同?

这个问题的理论面貌如下:

我有以下代码(Link 到 JSBin (online JS execution environment)

l = console.log

const g = (title) => {
    return (a) => {
      l(title + a)
      return a+1;
    }
};

const gA = g("A ")
const gB = g("B ")

const throwError = (title) => {
    return (a) => {
      l(title + a)
      throw new Error("Error from promise " + title + a)
    }
}; 

promise = new Promise((resolve, reject) => {
  resolve(1)
})

l("Started application")

promise
  .then(gA)
  .then(gA)
  .then(throwError("A "))
  .catch(err => {
    l(err.message);
  })


promise
  .then(throwError("B "))
  .then(gB)
  .then(gB)
  .catch(err => {
    l(err.message);
  })

l("Finish main function")

解析为控制台中的以下输出

"Started application"
"Finish main function"
"A 1"
"B 1"
"A 2"
"A 3"
"Error from promise A 3"
"Error from promise B 1"

如果要按照注册的顺序执行承诺回调,我希望此输出中的 "Error from promise B 1" 更高。但他们最终出现了。 为什么会这样?

当您调用 resolve() 时,承诺履行/拒绝会排入承诺微任务队列。然后当任务获得 运行 时,所有相应的 .thens / .catchs 附加到 that promise 按附加顺序获得 运行 .

 promise.then(first);
 promise.then(second);

现在 .then returns 本身就是一个 Promise,它的 resolve 在执行回调时被调用。因此,附加到 .then 返回的 Promise 的 .then 至少在一个微任务之后执行:

 const secondPromise = firstPromise.then(first);
 // one microtick after first run, secondPromise fullfills, and therefore attached .thens get run
 secondPromise.then(second);

Do .then, .catch and .finally land in JS Event Loop immediately after being registered or somehow differently?

那些 promise 方法本身永远不会进入队列。任务队列包含 promise reactions,基本上就是 "run callbacks X/Y on the result of promise Z"。 (而且它们总是成对的 then 回调,因为那是 catchfinally 内部使用的)。

这些承诺反应会在承诺被解决后立即安排,或者在承诺已经解决后的 then 调用期间立即安排。

If promise callbacks were to be executed in the order they were registered

他们是。但这仅 per promise 成立。您的代码中唯一要附加多个回调的承诺是 promise,并且 gA 运行 早于 throwError("B ")。无法保证附加到不同承诺的回调,因为这些承诺无论如何都会在不同时间结算。

根据您分享的代码,让我们向以下承诺 A:

promise
  .then(gA)
  .then(gA)
  .then(throwError("A "))
  .catch(err => {
    l(err.message);
  })

并向以下承诺 B:

promise
  .then(throwError("B "))
  .then(gB)
  .then(gB)
  .catch(err => {
    l(err.message);
  })

然后我们知道 promise 的异步行为,console.log 将始终在执行之前完成,因此它首先打印但同时 promise A 和 B 都已经开始但将在 console.log 之后开始打印s.

根据顺序,即首先承诺 A,然后承诺 B,两者都落在他们的第一个 .then 上,即执行承诺 A -> .then(1st) 然后执行承诺 b -> .then(1st) 因此它打印

"A 1" //no exception called here hence will start execution of next .then
"B 1" //prints from throw called here and remains alive with 1 hence will never allow any of next .then() to execute.
"A 2" // 2nd .then executed
"A 3" // 3rd .then executed followed by throw and again remains alive with 3

如果发生错误则进入catch,然后"throw"总是最后执行完,所以按照promise A在promise B之前的顺序,如下图

"Error from promise A 3" // 3 because of last successful increment
"Error from promise B 1" // 1 because of throw did not allow increment

所以这是我相信的顺序,如果 .then() return 级联承诺那么它取决于响应解决的时间。