Manual implementation of promise source code

Time:2021-12-2
Promise is an asynchronous solution to the callback problem. Promise is syntactically a constructor. Functionally, it encapsulates asynchronous operations and can obtain their operation results.

1. Basic usage

const p =new Promise((resolve,reject)=>{
        setTimeout(()=>{
            //Asynchronous operation
            resolve(value)
        },100)

    })

The parameters of the constructor promise are an executor function, and the parameters of the executor function are resolve and reject, respectively: the first callback function is called when the state of the promise object changes to resolved, and the second callback function is called when the state of the promise object changes to rejected
2. Implementation of promise constructor

The promise object contains three states. The initial value is pending, resolved and rejected
Internal state during execution, the state can only be changed once and is irreversible.

At the beginning of initialization, the status is pending callbacks, which is used to save successful and failed callback functions

self.status =PENDING
        self.data =undefined
        Self. Callbacks = [] // each element structure {onresolved() {} onrejected() {}}
function Promise(excutor){
        const self =this
        self.status =PENDING
        self.data =undefined
        Self. Callbacks = [] // each element structure {onresolved() {} onrejected() {}}
        function resolve(value){
            //The resolve function changes the promise state to resolved
            if(self.status!==PENDING){
                //If the status is not pending, return directly
                return
            }
            self.status =RESOLVED
            self.data = value
            if(self.callbacks.length>0){
               setTimeout(() => {
                    self.callbacks.forEach(callbacksObj => {
                        callbacksObj.onResolved(value)
                        
                    });  
                },0);
    
            }
        }
        function reject(reason){
            if(self.status!==PENDING){
                return
            }
            self.status =REJECTED
            self.data = reason
            if(self.callbacks.length>0){
               setTimeout(() => {
                   //Traverse callback queue
                    self.callbacks.forEach(callbacksObj => {
                        callbacksObj.onRejected(reason)
                        
                    });  
                });
    
            }

        }
       //Synchronize execution now
       try{
        excutor(resolve,reject)

       }catch(err){
           reject(err)
       }       
    }

3. Then method of promise instance

The first parameter of the then method is the callback function in the resolved state, and the second parameter is the callback function in the rejected state. They are optional. And the return is also a promise object. There are three cases
  • If the callback function returns a promise return, the result of the promise is the result of the promise
  • If the callback function returns a promise other than promise return, it will succeed. Value is the return value
  • If an exception is thrown, the promise of return will fail. Resaon is error
Promise.prototype.then=function(onResolved,onRejected){
        const self =this
        onResolved = typeof onResolved === 'function' ? onResolved :value =>value
        onRejected = typeof onRejected === 'function' ? onRejected :reason =>{throw reason}
        //Returns a new promise object 
        return new Promise((resolve,reject)=>{
        //Call the specified callback function to process and change the promise state of return according to the execution result
        function handle(callback){
            try{
                const result =callback(self.data)
                if(result instanceof Promise){
                    //If the callback function returns the result of the promise return, it is the result of the promise
                    result.then(value =>{
                         resolve(value)

                    },reason =>{
                         reject(reason)

                    })
                    // result.then(resolve,reject)

                }else{
                    //If the callback function returns a promise that is not a promise return, it will succeed. The value is the return value
                    resolve(result)
                }
            }catch(error){
             //If an exception is thrown, the promise of return will fail. Resaon is error
                reject(error)

            } 
        }
            if(self.status === PENDING){
                self.callbacks.push({
                    onResolved(){
                        handle(onResolved)
                    },
                    onRejected(){
                        handle(onRejected) 
                    }
                })
    
            }else if(self.status === RESOLVED){
                setTimeout(()=>{
                    handle(onResolved)
                })
    
            }else{
                setTimeout(()=>{
                    handle(onRejected)
                })
            }
        })
         
    }

4. Catch method of promise object

Function to capture the callback method in which the error occurred
    Promise.prototype.catch=function(onRejected){
        return this.then(undefined,onRejected)  
    }

5 resolve method of promise

The function is to change the object into promise object. If the resolve method parameter is a non promise object, pass value directly. If it is a promise object, the result of value will be the result of promise
Promise.resolve = function(value){
        return new Promise((resolve,reject)=>{
            //Value is promise
            if(value instanceof Promise){
                //Use the result of value as the result of promise
                value.then(resolve,reject)
            }else{
                  //Value is not promise
                  resolve(value)
            }
        })
    }

6. Reject method of promise

The action returns a rejected promise object
    Promise.reject = function(reason){
        return new Promise((resolve,reject)=>{
            reject(reason)
        })
    }

7. Promise’s all method

Function: execute multiple promises and return new promise instances
  The all method receives an array parameter:
  • If the promise objects are all successful, an array will be returned to hold the return value of each successful promise.
  • If a promise object fails, the new promise will become a failure. The return value is the return value of the promise that failed to execute
Promise.all = function(promises){
        //An array used to hold all successful values
        const values =new Array(promises.length)
        //Number of successful promises saved
        let count = 0 
        return new Promise((resolve,reject)=>{
            //Get the result of each promise
            promises.forEach((p,index)=>{
                Promise.resolve(p).then(value=>{
                    count++
                    Values [index] = value // values saved successfully
                    //If all are successful, change the promise of return to success

                    if(count === promises.length){
                        resolve(values)
                    }
                },reason =>{
                    reject(reason)
                })

            })
        })

    }

8. Promise race method

Function: returns a new promise object. The return value of the first completed promise is used as the result of the new promise object
Promise.race = function(promises){
        return new Promise((resolve,reject)=>{
            //Get the result of each promise
            promises.forEach((p)=>{
                Promise.resolve(p).then(value=>{
                    resolve(value)
                },reason =>{
                    reject(reason)
                })
            })
        })
    }