当我了解 microtask 和 Promise 时,我遇到了一个我不明白的行为

when I learned about microtask and Promise , I came across a behavior I don't understand

我没有return then() 回调里的东西,我认为输出应该是 1 5 7 2 6 3 4,但结果是 1 2 5 3 6 7 4,谁能告诉我为什么

Promise.resolve().then(function() {
    console.log('promise1');
    
    Promise.resolve().then(() => {
        console.log('promise2')

        Promise.resolve().then(() => {
            console.log('promise3')

            Promise.resolve().then(() => {
                console.log('promise4')
            })
        })
    })
}).then(function() {
    console.log('promise5');

    Promise.resolve().then(() => {
        console.log('promise6')
    })
}).then(() => {
    console.log('promise7')
})

好吧,这会很冗长。与其他人相反,我会声称,console.log 调用的执行顺序在这里是完全确定的。异步代码不一定总是这样,但是当没有任何“真正的”异步代码发生时,它仍然经常发生。

为清楚起见编号的代码:

01 Promise.resolve().then(function() {
02     console.log('promise1');
03     
04     Promise.resolve().then(() => {
05         console.log('promise2')
06 
07         Promise.resolve().then(() => {
08             console.log('promise3')
09 
10             Promise.resolve().then(() => {
11                 console.log('promise4')
12             })
13         })
14     })
15 }).then(function() {
16     console.log('promise5');
17 
18     Promise.resolve().then(() => {
19         console.log('promise6')
20     })
21 }).then(() => {
22     console.log('promise7')
23 })

温馨提示:Javascript是单线程的,只能同时运行一个。

下面每一步都是代码执行,直到释放上下文,再加上promise resolving 因为函数返回。省略了一些调用(例如 Promise.resolve()),因为它很明显,会发生什么。

在每个步骤结束时,我将列出当前队列和已执行的 comment.log 个调用。由于每个函数都以 console.log 调用开头,具有唯一编号,因此我也将使用它们作为函数的名称。

注意:当一个函数结束时,它又解析了一个空的 promise [[PromiseFulfillReactions]],我不会提到它,因为它不重要。


程序开始运行宁...

  • 01 Promise.resolve().then(function() { 被调用并入队 1
  • 15 }).then(function() { 在未解决的承诺上被调用(来自第 1 行的 then),等待它解决
  • 21 }).then(() => { 在未解决的承诺上被调用(来自第 15 行的 then),等待它解决

排队的任务:[1]

已经执行的日志:[]


  • 02 console.log('promise1');执行
  • 04 Promise.resolve().then(() => { 被调用并入队 2
  • 返回 undefined,一个非对象(当然不是 then-able,不是一个 promise),导致解析从第 1 行的 then 返回的 promise,这反过来导致它的 [[PromiseFulfillReactions]] 待执行。唯一添加的反应来自 15 }).then(function() {(见上文)。这会使 5.
  • 入队

排队的任务:[2, 5]

已经执行的日志:[1]


  • 05 console.log('promise2')执行
  • 07 Promise.resolve().then(() => { 被调用并入队 3

排队的任务:[5, 3]

已经执行的日志:[1, 2]


  • 16 console.log('promise5');执行
  • 18 Promise.resolve().then(() => { 被调用并入队 6
  • 返回,与上面类似,解决了从 15 }).then(function() { 返回的承诺,因此它的 [[PromiseFulfillReactions]] 被执行。这会使 7
  • 排队

排队的任务:[3, 6, 7]

已经执行的日志:[1, 2, 5]


  • 08 console.log('promise3')执行
  • 10 Promise.resolve().then(() => { 被调用并入队 4

排队的任务:[6, 7, 4]

已执行的日志:[1, 2, 5, 3]

为了完成,我将添加最后的步骤,但从这里开始非常简单。


  • 19 console.log('promise6')被执行

排队的任务:[7, 4]

已执行的日志:[1, 2, 5, 3, 6]


  • 22 console.log('promise7')被执行

排队的任务:[4]

已执行的日志:[1, 2, 5, 3, 6, 7]


  • 11 console.log('promise4')被执行

排队的任务:[] 空!

已经执行的日志:[1, 2, 5, 3, 6, 7, 4]


程序终止。