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

Tags: , ,



I didn’t return something in then() callback, In my opinion the output should be 1 5 7 2 6 3 4,but the result is 1 2 5 3 6 7 4, who can tell me why

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')
})

Answer

Alright, this will be very verbose. Contrary to others, i’ll claim, that the execution order for the console.log calls is completely deterministic here. This doesn’t always have to be the case with async code, but when there isn’t any “real” async code happening, it still often is.

Code numbered for clarity:

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 })

Reminder: Javascript is single-threaded, only one can run at the same time.

In the following, each step is code execution until the context is released, plus promise resolving because of the function returning. Some calls are omitted (e.g. Promise.resolve()), because it’s kind of obvious, what happens.

At the end of each step, i’ll list the current queue, and already executed comment.log calls. As every function begins with a console.log call, with a unique number, i’ll use those as names for the functions as well.

Note: When a function ends, which in turn resolves a promise, which has empty [[PromiseFulfillReactions]], i won’t mention it, as it’s not important.


Program starts running…

  • 01 Promise.resolve().then(function() { is called and enqueues 1
  • 15 }).then(function() { is called on an unresolved promise (from the then in line 1), wait for it to resolve
  • 21 }).then(() => { is called on an unresolved promise (from the then in line 15), wait for it to resolve

Queued tasks: [1]

Already performed logs: []


  • 02 console.log('promise1'); executes
  • 04 Promise.resolve().then(() => { is called and enqueues 2
  • Returning undefined, a non-object (certainly not then-able, not a promise), causes resolving of the promise returned from then in line 1, which in turn causes its [[PromiseFulfillReactions]] to be performed. The only added reaction is from 15 }).then(function() { (see above). This enqueues 5.

Queued tasks: [2, 5]

Already performed logs: [1]


  • 05 console.log('promise2') executes
  • 07 Promise.resolve().then(() => { is called and enqueues 3

Queued tasks: [5, 3]

Already performed logs: [1, 2]


  • 16 console.log('promise5'); executes
  • 18 Promise.resolve().then(() => { is called and enqueues 6
  • Returning, similar to above, resolves the promise returned from 15 }).then(function() {, so its [[PromiseFulfillReactions]] are performed. This enqueues 7

Queued tasks: [3, 6, 7]

Already performed logs: [1, 2, 5]


  • 08 console.log('promise3') executes
  • 10 Promise.resolve().then(() => { is called and enqueues 4

Queued tasks: [6, 7, 4]

Already performed logs: [1, 2, 5, 3]

I’ll add the last steps for completion’s sake, but from here it’s very straight forward.


  • 19 console.log('promise6') is executed

Queued tasks: [7, 4]

Already performed logs: [1, 2, 5, 3, 6]


  • 22 console.log('promise7') is executed

Queued tasks: [4]

Already performed logs: [1, 2, 5, 3, 6, 7]


  • 11 console.log('promise4') is executed

Queued tasks: [] empty!

Already performed logs: [1, 2, 5, 3, 6, 7, 4]


program terminates.



Source: stackoverflow