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