Starting with the point of the argument, and some questions about the Promise, we backtrace our argument through the source code
- The code in the Promise function body executes immediately (the code in the new Promise() function body executes immediately)
- This is very depressing. The state of Promise is irreversible
- Promises are microtasks. When do you start pushing the microtask queue? (New Promise? Resolve ()? Then ()? Or??)
- Why does a return value in a.THEN become an incoming argument to the next.then?
- What is the underlying implementation of Promise microtasks?
To solve these problems, just look at the SRC /core.js under the promise
The ASAP package that promise relies on is basically pushing microtasks into the microtask queue
Let’s define a Promise call and use the defined Promise to analyze the source code
const p1 = new Promise((resolve, reject) => {
console.log(1)
resolve('Promise resolve 1')
}).then(r => {
console.log(2, r)
return 3
}).then(r => {
console.log(r)
})
Copy the code
Let’s look at the source code
Promise constructor
First, let’s find the constructor for Promise
The input fn is the body of the function you pass in Promise, and the body fn is evaluated twice
- The function will determine if it is a function, and if it is not, it will throw an exception
- If noop is equal to noop, return noop
Why do we add this judgment
We see that an empty function called noop is declared at the top of the source code, so the first time the PROMISE is entered, the FN must not be equal to noop, so the judgment is meaningless. Look down with questions.
DoResolve (changes the state of a Promise)
DoResolve () is executed, the first argument is the body of the Promise function, and the second argument is passed this, which is an instance of the Promise
Give a marked variable done = false
TryCallTwo (used to execute the Promise body)
We then execute tryCallTow. The first argument is fn (the body of the promise function), the second argument is a function that executes resolve(), and the third argument is a function that executes reject
Var res in doResolve should be the result of fn(a, b)
The execution of FN is equivalent to the body of the function
(resolve, reject) => {
console.log(1)
resolve('Promise resolve 1')
}
Copy the code
A and B are the same as resolve and reject
So after fn executes, there is no asynchronous operation before resolve, which proves the first argument,
The code inside the body of the new Promise function is executed immediately
We then execute resolve(‘Promise resolve 1’) in the body of the function, which is equivalent to executing function as the second argument to tryCallTwo in the source code
Return done (true); That’s why promise’s state is irreversible,
In the resolve and reject methods that are executed later, the current promise instance is marked with a state where done is already true. In the body of the function, a return of either resolve or reject done is true. Which proves the second argument that Promise’s state is irreversible
Resolve (sets the state and value of the Promise)
Then we continue to execute resolve(promise, value) in the source code. One parameter is the Promise instance, The second is the input to resolve(‘Promise resolve 1’), ‘Promise resolve 1’, which is the value of the Promise
NewValue == ‘Promise resolve 1’ newValue == ‘Promise resolve 1’ Check complex Promise values such as resolve(function (){}) or. Then return a new Promise
This is very depressing. This is very depressing. This is very depressing.
Now, I can find out how long the link is. It’s not time to postpone the task.
_deferredState = 0, so neither of them passes. At this point, the Promise is completely executed, and there is no push microtask. In the case of new Promise, you can rule out that the Promise is not in the case of new Promise, but in the case of resolve
Will it be in… then? In the case of ‘resolve’ or ‘reject’, the code in the ‘. Then ‘is executed in the case of’ resolve ‘or’ reject ‘. Look down with questions.
Look at the.then code. It takes two arguments, the first successful callback and the second exception callback
If not, it will give you a new Promise and then execute the following code
The safeThen method in the source code is something that you can look at and not post here.
Noop (); noop (); Promise (); noop ()
If (fn === noop) return; The doResolve(fn, this) method does not execute; When doResolve is executed, done is set to true, and the promise state is marked, but the promise state is irreversible. In this case, the then method needs to return a stateless (peding) promise
Next look at the handle method executed by then
The first argument calls for a successful callback, the second argument calls for a failed callback, and the third argument is a new Promise instance
Ok, so we’re just going to assign these three properties to the instance, and we’re going to determine if the next callback is of type function
Note that a new promise instance stored in this.promise = PROMISE will eventually be returned so that a chained call to a promise can be implemented.
handle
The handle method in the then method is one of the more complicated methods in the PROMISE method. You can also write your own code breakpoints and enter this method to make it clearer
Self._state we know it’s already set to 1 when we go into resolve so the first while loop skiffs,
Promise.onHandle with an initial value of null is skipped
Self._state === 0 is also skipped and goes directly to handleResolved
HandleResolved (Push microtask to microtask queue)
Finally. Var asap = require(‘asap/raw’); Refers to an asynchronously called method that pushes the current function body to the microtask queue
This method is in the directory of the referenced ASAP browser-raw.js (browser environment)
asap
The core push-to-queue code is directly pasted here
As you can see in the browser environment, the microtask queue is pushed through the MutaionObserver API
MutaionObserver
An API that listens for changes in dom elements and pushes a microtask into the microtask queue
So here a microtask is pushing the microtask queue, and then it’s going to chain call the next then, so let’s look at the next — what’s the next then? Will you continue to push tasks into the microtask queue?
So let’s be careful here. The “this” that enters the THEN method refers to a Promise that was reinitialized in the last THEN method. The state of each Promise is initialized and has not changed or been assigned because noop has not executed doResolve
_deferredState === 0; The new Promise instance (returned to the next.then Promise instance) is assigned to self._DEFERrefs, and then returns out. The handleResolved method is not implemented, so the body of the then method is not pushed to the microtask queue, only _deferredState is marked on the promise instance
When will the later then method be pushed into the microtask queue?
That’s the question. Then the tasks behind are also micro tasks.
Continue with our code.
This is what happens next after the Promise executes all the.then. Based on the browser’s event loop,
After the code in the main stack is executed, the queue of microtasks in the stack will be executed, that is, the number of microtasks in the queue is 1, so it is time to execute this task.
The callback function is performed through ASAP
This is fulfilled fulfilled by determining that self._state is 1.
Cb === null is skipped
So let’s look at the RET variable
tryCallOne
First argument then method resolve function, second argument Promise value (‘Promise resolve 1’)
This function assigns the value of fn to the variable ret
Resolve (deferred. Promise, RET)
Now, how can self._deferredState be equal to 1? Remember, before then, after then. That’s the 1 that was punched at that time
So it goes from the finale method to the handle where _state is equal to 1 and the Promise that has been resolved has been executed
So the process is over and done
May be a little around, the first time to write an article, describe the wrong place please correct