First, analyze the implementation process of Promise
A Promise is a big pity, which must be fulfilled soon. When this class is implemented, an actuator needs to be passed in, which will be executed immediately. There are three states in the Promise, which is a pity success, Rejected failure pending wait
- This is a big pity
- Pending -> Rejected failed
Resolve and reject are used to change the state; Set the result of the object
- resolve: fulfilled
- reject: rejected
If (resolve, resolve, and resolve) then (resolve, resolve, and fail) then (resolve, resolve, and fail Reject is an asynchronous operation whose state is pending and how the state changes, so you need to store successful and failed callbacks in the instance properties. So you can execute successful and failed callbacks in resolve and Reject. If you call MyPromise’s then method several times, you can change the state of resolve and Reject synchronously, but asynchronously. 9. The then method can be called chained. To implement chained calls, the then method returns a new MyPromise and returns the value of the callback from the previous THEN method. 10. The value returned by the THEN method, which may be a normal value or a MyPromise, is called in MyPromise. Resolve, reject, 11. If the then method returns a MyPromise and the MyPromise is the return value of the then method, a loop call to MyPromise will occur, which will result in an error. 12, here to deal with two exceptions, is a constructor actuator code execution of exception Another method is then callback exceptions in 13, then method compatible with asynchronous operations in different conditions of 14, then method of parameter is optional, when passing a parameter or what all don’t pass, how to deal with? 15. A promise object has a static method, All, that executes promises in batches and receives an array of returned results. If one of them fails, the failed callback function is called.
Two, code implementation
// There are three states in this Promise, which is a pity success and rejected failure pending
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// Promise is a class
class MyPromise {
// 1.2, when executing the class, we need to pass in an executor, and the executor will execute immediately
constructor(exexcutor) {
Handle one of two exceptions: the code execution exception of the executor in the constructor
try {
// 3.1, resolve, and reject change the state of the object; The result of setting the object
exexcutor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING
value = undefined
reason = undefined
If the state is changed asynchronously, you need to store multiple successful and failed callback functions in sequence (synchronous compatible).
successCallFn = []
failureCallFn = []
// 7.1, resolve and REJECT know when asynchronous operations are called back, so you can execute successful and failed callbacks in resolve and reject
resolve = (value) = > {
// due to pending -> fulfilled pending -> rejected fail
if (this.status ! == PENDING)return
this.status = FULFILLED
this.value = value
After the asynchronous operation is complete, call the previously stored callback functions
while (this.successCallFn.length) this.successCallFn.shift()()
}
reject = (reason) = > {
if (this.status ! == PENDING)return
this.status = REJECTED
this.reason = reason
while (this.failureCallFn.length) this.failureCallFn.shift()()
}
// 13.1. Asynchronous operations are compatible with different states in the then method
then (successCallFn, failureCallFn) {
// Then method parameters are optional. What happens when a parameter is passed or nothing is passed?
successCallFn = successCallFn ? successCallFn : value= > value
failureCallFn = failureCallFn ? failureCallFn : reason= > { throw reason }
The then method can be called chained. To implement the chained call, then returns a new MyPromise
let promise2 = new MyPromise((resolve, reject) = > {
// the then method is used to determine the state
// this is a big pity. If the status is FULFILLED, the callback function will be called successfully. If the status is FULFILLED, the callback function will be called failed
if (this.status === FULFILLED) {
// perform asynchronous execution to obtain the promise2 instance
setTimeout(() = > {
// handle the second of two exceptions: then method callback exception
try {
The success callback takes an argument called this.value, which is the result of the resolve object
The value returned by the then method, which may be a normal value or a MyPromise, encapsulates the paserPomiseX process
let x = successCallFn(this.value)
paserPomiseX(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else if (this.status === REJECTED) {
setTimeout(() = > {
try {
The reject callback takes this. Reason, which is the result of the reject setting
let x = failureCallFn(this.reason)
paserPomiseX(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)}else if (this.status === PENDING) { // The current state is pending. How to change the state?
this.successCallFn.push(() = > {
When resolve and reject are asynchronously changed, the state of the method is pending
setTimeout(() = > {
try {
let x = successCallFn(this.value)
paserPomiseX(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})this.failureCallFn.push(() = > {
setTimeout(() = > {
try {
let x = failureCallFn(this.reason)
paserPomiseX(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)})}})return promise2
}
// No matter the last state of the promise, the callback specified by the finally method is executed after the callback specified by then or catch.
finally (callfn) {
Then fetch the state of the instance object
return this.then(value= > {
return MyPromise.resolve(callfn()).then(() = > value)
}, reason= > {
return MyPromise.resolve(callfn()).then(() = > { throw reason })
})
}
// The Promise object is a 'bubble' that will be passed back until it is caught. That is, errors are always caught by the next catch statement.
catch (failureCallFn) {
return this.then(undefined, failureCallFn)
}
The promise object has a static method all, which executes promises in batches and receives an array of returns. If one of the returns fails, the failed callback function will be called.
static all (array) {
let index = 0
let result = []
// 15.2, myPromise. all returns a Mypromise object
return new MyPromise((resolve, reject) = > {
// Define a function for the change result array
function addData (key, value) {
result[key] = value
index++
// 15.4. Check that all promise objects in the array are finished
if (index === array.length) {
resolve(result)
}
}
for (let i = 0; i < array.length; i++) {
const current = array[i]
// Check whether a single element in the array is MyPromise
if (current instanceof MyPromise) {
current.then(value= > addData(i, value), reason= > reject(reason))
} else {
/ / common values
addData(i, array[i])
}
}
})
}
A static resolve method is used to convert an existing Promise object into a Promise object to control the asynchronous process.
static resolve (value) {
if (value instanceof MyPromise) return value
return new MyPromise(resolve= > resolve(value))
}
}
function paserPomiseX (promise2, x, resolve, reject) {
If the then method returns a MyPromise, and the MyPromise is the return value of the then method, a loop call to MyPromise will occur, and an error will be reported during execution.
if (promise2 === x) {
reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
return
}
if (x instanceof MyPromise) {
Resolve, reject, value, reason; // If MyPromise is used, then call resolve, reject, value, reason
x.then(resolve, reject)
} else {
The then method returns a normal value
resolve(x)
}
}
Copy the code