preface

The origin of this blog is a friend’s share 👇🏻

Originally from: juejin.cn/post/684490…

I was originally confident about the promise principle, but under the torture of difficult and strange problems, I still broke the barrier… Here’s a rundown of promise’s mechanics and some of the quirks.

Conclusion first

Here’s how the Promise system works:

  1. The THEN method executes synchronously, but the callback in somePromise.then(callback) is scheduled as a microtask (added to the microtask queue or registered on the innerList).

  2. The somePromise.then(callback) method neither executes nor joins the microtask queue when somePromise is in the pendding state. Instead, it is stored in a registration queue (tentatively called innerList) within somePromise.

  3. The innerList will add the callbacks from the queue to the microtask queue the moment the Promise object’s state becomes fulfilled.

  4. If the callback is passed without a return value, the Promise object with the state fulfilled and the parameter undefined will be returned by default. If the return value value is written, the promise object with the state fulfilled and parameter value is returned.

    somePromise.then(() = >{
        console.log(something)
        // return undefined
        // return value
    })
    Copy the code
  5. ⭐️ Weirdest rule: resolve(promise.resolve ()) takes 2 microtasks.

    See example 2 in this article.

    somePromise.then(() = >{ 
            return Promise.resolve() 
            Return promise.resolve () in then is equivalent to resolve(promise.resolve ())
    }.then(() = >console.log('resolve'))
    Copy the code

Understanding this is the key to dealing with promise problems

① Basic cognition

new Promise((resolve, reject) = > { // Called: promise1
    resolve(); 
})
    .then(() = > { console.log("Log: first then"); }) // Call it: then1
    .then(() = > { console.log("Log: second then"); }) // Call it: then2
Copy the code

See this question you may begin to wonder, so simple topic also used to do an example? Yeah, you all know that the output order for this problem is going to be

Log: the first THEN log: the second THENCopy the code

But not everyone knows exactly how it works.

  1. Use a table to record the execution and execute all the synchronized code as a macro task
Microtask queue Current execution context
[] Global context
  1. This is very depressing. This is very depressing. This is very depressing
Microtask queue Current execution context
[ then1-callback ] Global context
  1. When the second THEN is encountered, the then1-promise is still in the state of Pendding because the then1-callback has not been executed. At this point, the then2-callback is registered in the innerList of the THEN1-promise.
Microtask queue Current execution context then1-promise-innerList
[ then1-callback ] Global context [ then2-callback ]
  1. After the macro task is completed, the microtask queue is retrieved and executed in sequence.
Microtask queue Current execution context then1-promise-innerList
[] then1-callback [ then2-callback ]
  1. Print “log: first THEN “, return undefined. This is fulfilled. The then1-promise state becomes fulfilled, and the transmission value is undefined. The then1-innerList is immediately taken out and added to the microtask queue
Microtask queue Current execution context
[ then2-callback ] then1-callback
  1. Fetch the next microtask and execute, print “log: second then”
Microtask queue Current execution context
[] then2-callback
  1. The microtask queue is cleared and no new macro task is created. The execution is complete.

② Resolve = 2 then??

Let’s take a look at this surprising rule

new Promise(resolve= > { // promise1
    resolve(Promise.resolve())
}).then(() = > {
    console.log('resolved') // then0
})

Promise.resolve() // promise2
   .then(() = > { console.log('1')})// then1
   .then(() = > { console.log('2')})// then2
   .then(() = > { console.log('3')})// then3
Copy the code

Look at this code and say your answer first. The answer is: 1, 2, Resolved, 3 Let’s review the implementation process

  1. Initialize table
Microtask queue Current execution context
[] global
  1. Resolve (promise.resolve ()), according to our rule, consumes two microtasks: push the first microtask first.
Microtask queue Current execution context
[First microtask consumed by promise1] global
  1. This will be fulfilled gradually. This will be fulfilled gradually. This will be fulfilled gradually, since the state of PromisE1 is not yet fulfilled
Microtask queue Current execution context promise1-innerList
[First microtask consumed by promise1] global [ then0-callback ]
  1. Perform THEN1, then2, then3. This is very depressing, because PromisE2 is already fulfilled, so then1-callback can be directly added to the microtask queue. The then2-callback and then3-callback are stored in the innerList of the THEN1-promise, respectively.
Microtask queue Current execution context promise1-innerList then1-promise-innerList then2-promise-innerList
Then1-callback (first microtask consumed, then1-callback) global [ then0-callback ] [ then2-callback ] [ then3-callback ]
  1. Take out the microtask “PromisE1 consumption of the first microtask” and execute, “PromisE1 consumption of the second microtask” into the microtask queue.
Microtask queue Current execution context promise1-innerList then1-promise-innerList then2-promise-innerList
[then1-callback, second microtask consumed by PromisE1] global [ then0-callback ] [ then2-callback ] [ then3-callback ]
  1. Take out the microtask then1-callback and print1This is very depressing. Fetch the task from the then1-promise-innerList and add it to the microtask queue.
Microtask queue Current execution context promise1-innerList then1-promise-innerList then2-promise-innerList
[Then2-callback] [Then2-callback] then1-callback [ then0-callback ] [] [ then3-callback ]
  1. Pick up the microtask “second microtask consumed” and execute it. This will eventually become fulfilled! Fetch the task in promise1-innerlist and add it to the microtask queue
Microtask queue Current execution context promise1-innerList then2-promise-innerList
[ then2-callback, then0-callback ] [] [ then3-callback ]
  1. Take out the microtask then2-callback and print2This is very depressing. Fetch the task from the then2-promise-innerList and add it to the microtask queue
Microtask queue Current execution context then2-promise-innerList
[ then0-callback, then3-callback ] then2-callback []
  1. Take out the microtask then0-callback and printresolved
Microtask queue Current execution context
[ then3-callback ] then0-callback
  1. Take out the microtask then3-callback and print3
Microtask queue Current execution context
[] then3-callback
  1. The microtask queue is cleared and no new macro task is created. The execution is complete.

Now look at this problem. Can you analyze it?

new Promise(resolve= > {
  resolve();
})
  .then(() = > {
    new Promise(resolve= > {
      resolve();
    })
      .then(() = > {
        console.log("Log: first internal THEN");
        return Promise.resolve();
      })
      .then(() = > console.log("Log: internal second THEN"));
  })
  .then(() = > console.log("Log: external second THEN"));
  
  // log: first internal then
  // log: external second then
  // log: internal second then
Copy the code