It took me a long time to sort out each flow in Promise.all (), and I made this note for review
The promise part of the source code is as follows, only to extract the part used
function Promise(excutor) {
const self = this
self.status = 'pending' // Add a status attribute to the Promise object, starting with pending
self.data = undefined // Assign the data attribute to the Promise object to store the result data
self.callbacks = [] {onResolved() {}, onRejected() {}}
function resolve(value) {
// If the current state is not pending, terminate
if(self.status ! = ='pending') {
return
}
// Change the status to Resolved
self.status = 'resolved'
// Save value data
self.data = value
// Execute onResolved asynchronously immediately if the callback function is waiting to be executed
if (self.callbacks.length > 0) {
setTimeout(() = > {// Put all successful callbacks into the queue
self.callbacks.forEach(callbacksObj= >{ callbacksObj.onResolved(value) }); }); }}function reject(reason) {
// If the current state is not pending, terminate
if(self.status ! = ='pending') {
return
}
// Change the status to Rejected
self.status = 'rejected'
// Save value data
self.data = reason
// Execute onRejected asynchronously immediately if the callback function is to be executed
if (self.callbacks.length > 0) {
setTimeout(() = > {// Put all successful callbacks into the queue
self.callbacks.forEach(callbacksObj= >{ callbacksObj.onRejected(reason) }); }); }}// Execute excutor immediately
try {
excutor(resolve, reject)
} catch (error) {// If the executor throws an exception, it fails
reject(error)
}
}
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
return new Promise((resolve, reject) = > {
if (self.status === 'pending') {
// Assume that the current state is pending
// The next line of this is the promise that calls the then method,
// Since this is in the excutor' of the new Promise,
this.callbacks.push({
onResolved: function () {
try {
// What is returned
// Return a promise
const result = onResolved(self.data)
if (result instanceof Promise) {
result.then(
value= > resolve(value),
reason= > reject(reason)
)
} else {
// Returns a value, which is wrapped as a promise and passed up
// Sort of recursively
resolve(result)
}
} catch (error) {
reject(error)
}
},
onRejected: function () {
try {
// What is returned
// Return a promise
const result = onRejected(self.data)
if (result instanceof Promise) {
result.then(
value= > resolve(value),
reason= > reject(reason)
)
} else {
// Returns a value, which is wrapped as a promise and passed up
// Sort of recursively
resolve(result)
}
} catch (error) {
reject(error)
}
}
})
}
}
/* The race() method of the Promise function object returns a Promise whose result is the state of the first completed Promise */
Promise.race = function (promises) {
return new Promise((resolve, reject) = > {
for (let i = 0; i < promises.length; i++) {
promises[i].then(v= > {
resolve(v)
}, r= > {
reject(r)
})
}
})
}
Copy the code
The sample code is as follows: Promise results are output asynchronously, and excutor uses setTimeout
let p1 = new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('1')},1000);
})
let p2 = new Promise((resolve, reject) = > {
// resolve('2')
setTimeout(() = > {
resolve('2')},1000);
})
let p3 = new Promise((resolve, reject) = > {
// resolve('3')
setTimeout(() = > {
resolve('3')},1000);
})
p1.aaa='I am the sign'
let result1 = Promise.race([p1,p2, p3])
console.log(result1);
Copy the code
The detailed process text is as follows: 1. First, three instance objects p1, P2 and P3 are created, but excutor is not executed and is temporarily placed in the asynchronous queue to wait for the completion of the synchronization task. 2. Inside promise.race: A new Promise is created, named newP for narrative purposes, which is the result in the test HTML, and the output
Promise.race = function (promises) {
return new Promise((resolve, reject) = > {
for (let i = 0; i < promises.length; i++) {
promises[i].then(v= > {
resolve(v)
}, r= > {
reject(r)
})
}
})
}
Copy the code
3.Enter the constructor code that constructs the newP object, where newP is pending and data is undefined, and enter the excutor of newP, which is the for loop 4.It will enter the then method of the first promise in promises array. The rest of the loop will be the same. Just describe the first loop,
Inside the constructor, a new Promise object is constructed, named insideP. Inside the constructor, insideP is pending and data is undefined
P1p2p3 is pending, so it will push an object {onResolved, onRejected} to the CALLbacks array of P1 5.The first loop is completed, and the subsequent loop is the same until the synchronization code is complete. At this point, the console prints result but the state of newP is pending (which will be automatically changed later). At this point, the asynchronous queue starts running, and p1p2P3 runs in sequence
Resolve (1) change p1PENDING to Resolved and data (1) because the callbacks array is pushed into an object in step 4.
In this case, setTimeout is set, so it will be put into the asynchronous queue, and then enter P2’s resolve(2). Similarly, P3’s resolve(3) will change the pending and data of P2 and P3 respectively, but will not enter the next operation, because it is asynchronous
The if statement in resolve, p1, will do the async operation and execute onResolved () 7.Go to the onResolved method inside the then method,And then because onResolved is an argument to then, jump to the argument where the then method was called, which is where the loop isYou can now see that the resolve() method is called,But make it clear who is calling the methodThe last article in this article documented this problem,
Resolve is called from the new Promise object in line 2, so this refers to the Promise (newP) instead of p1, which calls then.
Note: newP is pending and data is undefined; P1 is resolved and data is 1
8.Go to newP’s resolve method and change pending to Resolved and data to 1 because newP is resultIn fact, the result is already determined, because the result is already determined 9.Go back to the THEN method of P1 and determine what type of data will be returned by onResolved. This will not be a promise type. Resolve (result) will be entered in else 9.As you can see in the figure above, reslove is an excutor argument in the new Promise object of the then method. This is also stored by self, so when this method is called, Not p1, the external object that calls the then method, but this new Promise object, insideP as described above, emphasizing that insideP is pending and undefined, and insideP is resolved and 1 when resolve is executed.
10.
Then the onResolved loop for the first time will end and the second and third cycles will start because the asynchronous onResolved loops for P2P3 are already in the queue and the rest will be the same and the result will be the result in step 8.