The detailed process of realizing promise (implementing the most complete promise constructor)

Time:2020-11-24

1、 Create promise constructor infrastructure

  • Get status

    Status ='pending 'initialization 'resolved 'obtained

    Failed to get 'rejected'

  • Initial data

    data = undefined

  • Container function definition failed

    onResolved = undefined onRejected = undefined

  • Define success / failure function resolve / reject

    A kind of this.status Change status to obtained / get failed A kind of this.data Save success / failure data

    • If success / failure, the callback function is defined Immediate asynchronous success / failure callback
  • Execute success / failure function resolve / reject

    • If an exception is caught, the result of then retrun promise is failure

      Execute reject, pass in error

2、 Define the constructor prototype then function, receive success / failure callback onresolved / onrejected, and finally return a new promise instance

  • Define the return promise structure and receive success / failure function parameters. The execution result of return promise is determined by onresolved and onrejected

    1. Return promise defines dealwiththenreturn prompt (return promise state processing function) and accepts then’s success / failure callback = = = = > onresolved, onrejected has three results to change the status of return wealth

      The execution result is an exception throw. Execute the failure function of return promise and pass in the exception data

      The execution result is a promise instance. Whether the return promise calls the success / failure function depends on the promise result of the execution result

      If the execution result is not a promise instance, execute the success function of return promise and pass in the execution result

      Execute the success / failure callback passed in then and save the return value as result

      1. Result is an instance of promise

        Execute the result instance then method and call back the success / failure function of return promise in its success / failure

      2. Result is not a promise instanceExecute the return promise function and pass in result
      3. The result of result execution is exception throwCatch the exception and execute the return promise failure function. Pass in the error
  • Return promise defines three ways to process data acquisition status

    ====>There are three kinds of data acquisition situations, and each state must be asynchronous execution. If the data has been obtained successfully, it means that the data can be directly executed and the onresolved return value can be obtained. If the data acquisition fails, it means that the data can be executed directly and the onrejected return value data is not obtained. It means that onrejected and onresolved cannot be executed immediately, To be stored in the instance, it is executed by the callback function of the actuator

    1. Data acquisition successfulExecute the return promise state processing function and pass in the success callback function
    2. Data acquisition failedExecute the return promise state processing function and pass in the failure callback function
    3. Data not availableEncapsulate the success / failure function, execute the return promise state processing function in the encapsulated function, and pass in the then success / failure callback This wrapper function is ultimately executed by the success / callback function of the current promise instance Finally, the data is processed by the return promise state processing function

3、 Definition Promise.resolve

Promise.resolve Receive three types of parameters and return a new promise instanceSuccessful promise instance failed promise instance is not an arbitrary value of promise instance

Promise.resolve Return promise architecture Determine whether the parameter is a promise instance. If so, call the then method and bind the success / failure function of return promise The parameter is not promise. Call the return promise success function directly and pass in the parameter

4、 Definition Promise.all

Promise.all Receives an array of promise or other valuesIf all are successful, return promise will be executed and the result of promise will be passed in. If there is one failure, the failed return promise will be executed and the failure value will be passed in

Promise.all Return promise architecture Define an array container Define a counter Traverses the array (foreach), each time it enters the loop counter + 1 Execute each promise instance then. If successful, store the value in the array container according to the subscript Judge whether the promise array length is equal to the counter. If it is, it means that the return promise successful function needs to be executed If then fails, the return promise failure function is called directly and the then failure value is passed in

5、 Definition promise.rule

Promise.rule Receive an array of promise or other values. If a success / failure occurs, the return promise success / failure function is called directly

Implement the specific code

//! define common constants
//? not obtained, which means that the resolve of the current promise is completed asynchronously
const PENDING = 'pending'
//? obtained, which means that the current promise is executed synchronously
const RESOLVED = 'resolved'
//? failure, which means that the execution result of the current promise is failure
const REJECTED = 'rejected'
//! the three states can only be changed once from pending

function Promise(executor) {
    const _this = this
    //! promise constructor defines the initialization state as not obtained
    _this.status = PENDING
    //! promise constructor defines initialization data as undefined
    _this.data = undefined
    //! promise constructor definition initialization success container is undefined
    _this.onResolved = undefined
    //! promise constructor definition initialization failed, container is undefined
    _this.onRejected = undefined
    //! get success function
    function resolve(value) {
        //! if the status is not pending, return directly
        if (_this.status !== PENDING) { return }
        //! change status to get success
        _this.status = RESOLVED
        //! save data
        _this.data = value
        //! if the success function has been defined, it means that it needs to be executed asynchronously, successfully callback onresolved and pass in data
        if (_this.onResolved) {
            setTimeout(() => _this.onResolved(value));
        }
    }
    //! get failed function
    function reject(reason) {
        //! if the status is not pending, return directly
        if (_this.status !== PENDING) { return }
        //! change status to get failed
        _this.status = REJECTED
        //! save data
        _this.data = reason
        //! if the failure function has been defined, it means that the failure callback onresolved should be executed asynchronously and the data should be passed in
        if (_this.onRejected) {
            setTimeout(() => _this.onRejected(reason));
        }
    }
    try {
        executor(resolve, reject)
    } catch (error) {
        //! if an error is caught, the result of then retrun promise is failure
        //! then call the failure function of retrun promise directly, and fail to pass down
        reject(error)
    }
}
Promise.prototype = {
    then: function (onResolved, onRejected) {
        //! onresolved successful callback; onrejected failed callback;
        const _this = this
        //! when then is executed, a new promise is returned
        //The execution result of! Return promise is determined by onresolved and onrejected
        return new Promise((resolve, reject) => {
            /* 
            There are three kinds of data acquisition situations
            ! data has been obtained successfully, which means that it can be directly executed and the onresolved return value can be obtained
            ! data acquisition failed. It means that you can directly execute and get the returned value of onrejected
            ! if the data is not obtained, it means onrejected. Onresolved cannot be executed immediately. It should be stored in the instance and executed by the callback function of the actuator
            ! - > and each state must be executed asynchronously
            */
            if (_this.status === RESOLVED) {
                //! data acquisition successful, execute return promise status processing function, and pass in successful callback
                setTimeout(() => DealWithThenReturnPromise(onResolved));
            } else if (this.status === REJECTED) {
                //! data acquisition failed, execute return promise status processing function, and pass in failure callback
                setTimeout(() => DealWithThenReturnPromise(onRejected));
            } else {
                //! if the data is not obtained yet, encapsulate the success / failure function, execute the return promise state processing function in the encapsulated function, and pass in the then success / failure callback,
                //! this wrapper function is ultimately executed by the success / callback function of the current promise instance
                //! when getting data, it will be obtained in dealwiththenreturnpromise function
                _this.onResolved = value => DealWithThenReturnPromise(onResolved)
                _this.onRejected = reason => DealWithThenReturnPromise(onRejected)
            }
            //! define the return promise function and pass in the success / failure function to be processed
            function DealWithThenReturnPromise(callback) {
                /* 
                There are three conditions to change the status of "returned"
                ! the execution result is an exception throw. Execute the failure function of return promise and pass in the exception data
                Return / promise is the result of the successful execution of the function
                ! the execution result is not a promise instance. Execute the success function of return promise and pass in the execution result
                */
                try {
                    //! save then success / failure return value
                    const result = callback(_this.data)
                    if (result instanceof Promise) {
                        //! the execution result is a promise instance, which determines the execution result of return promise
                        //Easy to understand result.then (value=> resolve(value), reason=> reject(reason))

                        //! easy to write
                        result.then(resolve, reject)
                        //! here, the success / failure callback of return promise is passed into the execution result instance then, so the resolve here has double meanings, 
                        //! one is the onresolved and onrejected result instances of then, 
                        //The second is resolve and reject of return project
                    } else {
                        //! the execution result is not a promise instance. Execute the return promise successful function and pass in the execution result
                        resolve(result)
                    }
                } catch (error) {
                    //! the execution result is an exception throw. Catch the exception and execute the return promise failure function to pass in the exception
                    reject(error)
                }
            }

        })
    },
    catch: function (reject) { return this.then(null, reject) },
}
Promise.resolve = function (value) {
    /* 
    ! Promise.resolve Reception has three parameters
    ! 1. The instance result is failed
    ! 2. The instance result is successful
    ! 3. Not an instance
    */
    return new Promise((resolve, reject) => {
        if (value instanceof Promise) {
            //! if value is an instance of promise
            value.then(resolve, reject)
        } else {
            //! if not
            resolve(value)
        }
    })

}
Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
        reject(reason)
    })
}
Promise.all = function (promises) {
    //! create a counter
    let resolveCount = 0
    //! create array with specified length
    const values = new Array(promises.length)
    return new Promise((resolve, reject) => {
        promises.forEach((item, index) => {
            Promise.resolve(item).then(
                value => {
                    //! counter + 1 when successful
                    resolveCount++
                    //! promise instance succeeded. The result is saved in the array
                    values[index] = value
                    //! when the last one is executed, execute the all return promise success function and pass in the array of success values
                    promises.length === resolveCount ? resolve(values) : []
                },
                //! as long as there is a failure, the promise returned by all is a failure
                reason => reject(reason)
            )
        })
    })
}
Promise.rule = function (promises) {
    return new Promise((resolve, reject) => {
        promises.forEach(item => {
            Promise.resolve(item).then(resolve, reject)
        })
    })
}