ES6-Promise and Source Implementation

Beginning Instructions

The document ends with a complete Promise code handwritten in accordance with the Promise/A+ specification

Property value of promise instantiated object [promiseState]

  • pending wait
  • Resolution / fullfilled Success
  • reject failed

Property value of promise instantiated object [promiseResult]

  • Save the value returned by the asynchronous operation [success/failure]
  • Only the resolve and reject functions can modify this value

API for promise

Promise's constructor [Promise(executor){}]

  • Executor function: executor function such as (resolve, reject) => {}
  • resolve function: function executed after the internal success of the executor function
  • reject function: a function that is executed after an internal failure of an executor function

The contents of the executor function are called synchronously within Promise

Promise.prototype.then method [(onResolved, onRejected){}]

  • onResolved function: When the state of the Promise object becomes resolve, the callback function executed (value) => {...}
  • onRejected function: When the state of the Promise object becomes reject, the callback function executed (reason) => {...}

value and reason are the values returned by executing the resolve and reject functions
The then method will return a new Promise object

Promise.prototype.catch method [(onRejected){}]

  • onRejected function: When the state of the Promise object becomes reject, the callback function executed (reason) => {...}

The Promise.resolve method belongs to the Promise function object [(value) => {}]

  • Value is an inconsistent state of the Promise object returned because the value passed is different

Promise object returning resolve status returns value if value is an instantiated object that is not Promise
If value is Promise's instantiated object return status and return value are determined by the incoming Promise's instantiated object

    Promise.resolve(111) 
    /* promiseState='resolve' promiseResult=111 */

    Promise.resolve(true) 
    /* promiseState='resolve' promiseResult=true */

    Promise.resolve(new Promise(resolve,reject) => {
        resolve('OK')
        /* promiseState='resolve' promiseResult='OK' */

        reject('Error') 
        /* promiseState='reject' promiseResult='Error' */
    })

The Promise.reject method belongs to the Promise function object [(reason) => {}]

  • reason is the passed value Whatever value is passed in will eventually return a Promise object with a reject state

The Promise object from executing this function needs to call the catch function or the browser will fail

    Promise.resolve(111) 
    /* promiseState='reject' promiseResult=111 */
    
    Promise.resolve(true) 
    /* promiseState='reject' promiseResult=true */

    const myPromise =  Promise.resolve(new Promise(resolve,reject) => {
        resolve('OK') 
        /* promiseState = 'reject' promiseResult = new Promise(...)
           The status of the Promise object returned is resolve */

        reject('Error') 
        /* promiseState = 'reject' promiseResult = new Promise(...)
           The status of the Promise object returned is reject */
    })
    myPromise.catch((reason) => {
        console.log(reason)
    })

The Promise.all method belongs to the Promise function object [(promises) => {}]

  • promises is an array of promise objects that returns a new Promise object

If all Promise objects in promises have a status of resolve, the returned Promise has a status of resolve that is the return value of all successful objects in promises
If the state of an object in promises is reject, the returned Promise state is reject, which is the return value of the first failed object in promises.

The Promise.race method belongs to the Promise function object [(promises) => {}]

  • promises is an array of Promise objects that returns a new Promise object

The state of the Promise object returned is determined by the first object in the promises array to complete the state modification (setTimeout affects the final result)

Key Issues for Promise

Modification of Promise Object State

  • The resolve function makes the promiseStatus state resolve
  • The reject function and throw operation can change the state of promiseStatus to rejected

Promise object performs multiple callback functions

    let p = new Promise((resolve,reject) => {
        resolve('OK');
    })

    p.then(value => {
        console.log(value)
    })
    p.then(value => {
        alert(value)
    })

Multiple callback functions (then) can be specified for the Promise object to be executed in the order defined

Promise State Change and Order of Callback Function Execution

  • Situation 1 Synchronization Operation
    let p = new Promise((resolve,reject) => {
        resolve('OK');
    })
    p.then(value => {
        console.log(value)
    })

In this case, since the exector execution function is a resolve function that is called synchronously, the state-changing function is executed before the then callback function is executed.

  • Case 2 Asynchronous operations account for the vast majority of actual development
    let p = new Promise((resolve,reject) => {
        // Using delay functions to simulate the process of interface calls
        setTimeout(() => {
            resolve('OK');
        },1000)
    })
    p.then(value => {
        console.log(value)
    })

In this case, the resolve function is delayed for one second before it executes, so the callback function then executes until the promiseStatus value changes before calling the successful callback function

Return of Promise's callback function then

  • The callback function then of the promise object also returns the return value rules of a promise object, promiseStatus and promiseResult, which are consistent with Promise.resolve()

Chain call of Promise object

  • Chained invocation is supported because the promise object's callback function then returns a promise object as well

Promise's Exception Penetration

    let p = new Promise((resolve,reject) => {
        // resolve('OK)
        // throw 'ERR'
    }).then(value => {
        console.log(111)
    }).then(value => {
        console.log(2222)
    }).then(value =>{
        console.log(33333)
    }).catch(reason => {
        console.log(reason)
    })

There is no need to specify the wrong callback function for each of the then callback functions when making chain calls using Promise
Just add the catch callback at the end and the catch will be executed as long as the promiseResult state becomes rejected during the chain call

Termination of Promise

  • Because the promiseStatus value of the promise object returned by the then function's attribute determines the subsequent operation
  • So there is only one way to terminate an operation and return a promise object with a pending state
  • Returning true null or something like this is a resolve state throw operation that will be captured by the catch
    let p = new Promise((resolve,reject) => {
        resolve('Ok')
    }).then(value => {
        console.log(111);
        return new Promise(() => {});//promise object in pending state
    }).then(value => {
        console.log(2222)
    }).then(value =>{
        console.log(33333)
    }).catch(reason => {
        console.log(reason)
    })
    // Only 111 will be printed from the above code

Implement Promise according to Promise/A+ specification

function Promise(executor) {
    this.PromiseStatus = 'pending';
    this.PromiseResult = 'null';
    this.resolveCallbacks = [];
    this.rejectCallbacks = [];

    /**If not defined, this of the resolve and reject functions points to window s where the state and return values cannot be modified */
    const self = this 

    function resolve(data) {
        if(self.PromiseStatus !== 'pending') return ;
        self.PromiseStatus = 'resolved';
        self.PromiseResult = data;
        /**Processing asynchronous operations can have multiple callback functions */
        self.resolveCallbacks.forEach(onResolved => {
            onResolved(self.PromiseResult)
        })
    }

    function reject(data) {
        if(self.PromiseStatus !== 'pending') return ;
        self.PromiseStatus = 'rejected';
        self.PromiseResult = data;
        /**Processing asynchronous operations can have multiple callback functions */
        self.rejectCallbacks.forEach(onRejected => {
            onRejected(self.PromiseResult)
        })
    }

    try{
        /**resolve And reject are arguments */
        executor(resolve, reject);
    }catch(e){
        /**Handle throw throw throw exception */
        reject(e);
    }
}

Promise.prototype.then = function(onResolved, onRejected){
    const self = this;

    /**The return value must be a promise object */
    return new Promise((resolve,reject) => {
        /**Determines whether the user passes a parameter by default if the callback function is not returned */
        if(typeof onRejected !== 'function'){
            onRejected = (reason) => {
                throw reason
            }
        }
        if(typeof onResolved !== 'function'){
            onResolved = value => value
        }
        /**Encapsulation Processing Function */
        function callback(type){
            try{
                let result = type(self.PromiseResult);
                if(result instanceof Promise){
                    /*
                    **  Call the then method to determine if the status of the promise returned is successful or failed
                    **  If the result does not change its state then returning to pending state changes will take the then method
                    */
                    result.then(value => {
                        resolve(value);
                    }, reason => {
                        reject(reason);
                    })
                }else{
                    resolve(result);
                }
            }catch(e){
                /**Handle throw operation */
                reject(e)
            }
        }
        /**Call the corresponding callback function based on the value of PromiseStatus */

        /**Handling synchronization */
        if(this.PromiseStatus === 'resolved'){
            callback(onResolved);
        }
        if(this.PromiseStatus === 'rejected'){
            callback(onRejected);
        }

        /**Handling asynchronous cases The state of the promise object was not changed when the then method was executed */
        if(this.PromiseStatus === 'pending'){
            /*  
            **  Save successful and failed callback functions for resolve and reject calls in the Promise constructor
            **  Consider multiple then callback functions
            */
            this.resolveCallbacks.push(function(){
                callback(onResolved);
            });
            this.rejectCallbacks.push(function(){
                callback(onRejected);
            });
        }
    })
}

Promise.prototype.catch = function(onRejected) {
    return this.then(undefined,onRejected);
}

Tags: Javascript Front-end ECMAScript Promise

Posted on Sun, 12 Sep 2021 14:39:49 -0400 by Rustywolf