background
I saw a Promise title:
new Promise((resolve, reject) = > {
console.log('promise1')
resolve()
})
.then(() = > {
console.log('then11')
new Promise((resolve, reject) = > {
console.log('promise2')
resolve()
})
.then(() = > {
console.log('then21')
})
.then(() = > {
console.log('then23')
})
})
.then(() = > {
console.log('then12')})Copy the code
The output sequence is promise1, THEN11, promise2, then21, then23, then12. Promise1, then11, promise2, then21, then12, then23. Some unexpected recognition, so I found ES6-promise to understand the principle of its implementation.
Promise basic concept introduction
- Promise state: There are three states: Pending, fulfilled and Rejected. The initial state is pending.
- The above support chain calls, exceptions can pass through
.catch
To obtain.then
Second callback capture, also supports some finally, race, etc operations - The problem Promise addresses: I understand that it addresses asynchronous callbacks, asynchronous code exception catching.
The implementation process
The realization of the PromisePromise supports chained calls. Each call initiates a new Promise, and the return value of its onFulfill or onRjection callback is stored in the Result property of the newly returned Promise. That is, the number of chain calls that will result in the corresponding number of Promise instances:
new Promise(resolve= > {
resolve()
}).then(function() {
return 1
}).then(function(){
return 2
})
Copy the code
The corresponding Promise chain is:
RootPromise -> child1Promise(first then) -> child2Promise(second then)
Each Promise records the parameters passed in by its then or catch methods, which are triggered in the form of microtasks.
Returning to the example at the beginning of the document, add a name to the onFulfill callback from then:
new Promise((resolve, reject) = > { // This instance will be named A1 and then1 will be in the callback
console.log('promise1')
resolve()
})
// This then is named A1then
.then(function then1(){ // The newly returned empty Promise instance A11 will have then12 in the callback
console.log('then11')
new Promise((resolve, reject) = > { // The instance named B1 callback will exist then21
console.log('promise2')
resolve()
})
// B1then
.then(function then21() { // The newly returned empty Promise instance B12 will have then23 in the callback
console.log('then21')})// B12then
.then(function then23() {
console.log('then23')})})// A11then
.then(function then12() {
console.log('then12')})Copy the code
- Then A11then is added to the callback of A11, but not to the microtask queue.
- Then1 (B12then); resolve (B12then); then(B12then); then(B12then); Next, execute A11then, putting THEN12 into the microtask queue as well.
- Execute then21, change the state of the corresponding Promise, and place THEN23 in the microtask queue
- Perform then12
- Perform then23
The final output is promise1, THEN11, promise2, then21, THEN12, then23;
The chain call of a Promise, unlike our regular synchronous chain call, is not a one-time call, but a recursive process that determines whether the Promise callback needs to be placed in the microtask queue based on the current state of the Promise.
Putting a microtask on a queue is not an active action, but it can be done indirectly by using callback as a callback function to processs.nexttick (in the form of Node, which the browser can do via MutationObserver).
conclusion
By looking at es6-PROMISE source code to roughly understand the operation mechanism of promise, there are also a lot of different scenarios of adaptation, see the process also suggest handwritten code, enhance the understanding of the code.
Promises need to be understood by combining the Promise state with the callback function (then/catch callback). First, promises instance will hold the callback temporarily. If a Promise state switches, its callback will be added to the microtask queue waiting to be executed.