自定義Promise實現


前言

通過自定義編寫promise,可以更加深刻理解Promise的用法,以及學會對別人封裝的代碼做定制化使用。

自定義Promise

/**
 * 自定義Promise函數模塊,IIFE
 */
(function(window) {
    
    const PENDING = 'pending';
    const RESOLVED = 'resolved';
    const REJECTED = 'rejected';
    
    /**
     * Promise構造函數
     * executor: 執行器函數(同步執行)
     */
    function Promise(executor) {
        const self = this;
        self.status = PENDING; //給promise對象指定status屬性,初始值為pending
        self.data = undefined; //給promise對象指定一個用於存儲結果數據的屬性
        self.callbacks = []; //每個元素的數據結構: {onResolved(){}, onReject(){}}
        
        function resolve(value) {
            //如果當前狀態不是pending,直接結束
            if(self.status !== PENDING) {
                return;
            }
            
            //狀態為resolved
            self.status = RESOLVED;
            //保存value數據
            self.data = value;
            //如果有待執行的callback函數,立即異步執行回調函數onResolved
            if(self.callbacks.length>0) {
                setTimeout(() => {
                    self.callbacks.forEach(callbacksObj => {
                        callbacksObj.onResolved(value);
                    })
                })
            }
        }
        
        function reject(reason) {
            //如果當前狀態不是pending,直接結束
            if(self.status !== PENDING) {
                return;
            }
            //狀態為rejected
            self.status = REJECTED;
            //保存value數據
            self.data = reason;
            //如果有待執行的callback函數,立即異步執行回調函數onResolved
            if(self.callbacks.length>0) {
                setTimeout(() => {
                    self.callbacks.forEach(callbacksObj => {
                        callbacksObj.onRejected(reason);
                    })
                })
            }
        }
        
        try {
            executor(resolve, reject);
        } catch (error) { // 如果執行器拋出異常,primose對象變成rejected狀態
            reject(error);
        }
    }
    
    /**
     * Promise原型對象的then()
     * 指定成功和失敗的回調函數
     * 返回一個新的promise對象
     */
    Promise.prototype.then = function(onResolved, onRejected) {
        
        //向后傳遞成功的value
        onResolved = typeof onResolved === 'function' ? onResolved : value => value
        //指定默認的失敗的回調(實現錯誤/異常穿透的關鍵點),向后傳遞失敗的reason
        onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}
        
        const self = this;
        
        //返回一個新的promise對象
        return new Promise((resolve, reject) => {
            
            //調用指定的回調函數處理,根據執行的結果改變return的promise狀態
            function handle(callback) {
                /**
                 * 1.如果拋出異常,return的promise就會失敗,reason就是error
                 * 2.如果回調函數返回不是promise,return的promise就會成功,value就是返回的值
                 * 3.如果回調函數返回是promise,return的promise就是這個promise結果
                 */
                try {
                    const result = callback(self.data);
                    if(result instanceof Promise) {
                        // result.then(
                        //     value => resolve(value), //當result成功時,讓return的promise也成功
                        //     reason => reject(reason) //當result失敗時,讓return的promise也失敗
                        // )
                        result.then(resolve, reject);
                    } else {
                        resolve(result);
                    }
                } catch(error) {
                    reject(error);
                }
            }
            
            if(self.status === PENDING) {
                //假設當前還是pending狀態,將回調函數保存起來
                self.callbacks.push({
                    onResolved() {
                        handle(onResolved)
                    },
                    onRejected() {
                        handle(onRejected)
                    }
                })
            } else if(self.status === RESOLVED) { //如果當前是resolved狀態,異步執行onResolved函數並改變return的promise狀態
                setTimeout(() => {
                    handle(onResolved);
                })
            } else { //如果當前是rejected狀態,異步執行onRejected函數並改變return的promise狀態
                setTimeout(() => {
                    handle(onRejected);
                })
            }
        });
    }
    
    /**
     * Promise原型對象的catch()
     * 指定失敗的回調函數
     * 返回一個新的promise函數
     */
    Promise.prototype.catch = function(onRejected) {
        return this.then(undefined, onRejected);
    }
    
    // 函數對象方法,也即工具方法
    
    /**
     * Promise函數對象的resolve方法
     * 返回一個指定成功結果value的promise
     */
    Promise.resolve = function(value) {
        //返回一個成功/失敗的promise
        return new Promise((resolve, reject) => {
            //value是promise
            if(value instanceof Promise) {
                value.then(resolve, reject);
            } else { //value不是promise 
                resolve(value);
            }
        })
    }
    
    /**
     * Promise函數對象的reject方法
     * 返回一個指定失敗結果reason的promise
     */
    Promise.reject = function(reason) {
        //返回一個失敗的promise
        return new Promise((resolve, reject) => {
            reject(reason);
        })
    }
    
    /**
     * Promise函數對象的all方法
     */
    Promise.all = function(promises) {
        // 保存所有成功的value數組
        const values = new Array(promises.length);
        // 用來保存成功的promise的數量
        let resolvedCount = 0;
        return new Promise((resolve, reject) => {
            //遍歷獲取每一個primise的結果
            promises.forEach((p, index) => {
                Promise.resolve(p).then(
                    value => {
                        resolvedCount++; //成功的數量加1
                        values[index] = value; //p成功了,將成功的value按照順序保存到values中
                        //如果全部成功了,將return的promise改為成功
                        if(resolvedCount === promises.length) {
                            resolve(values);
                        }
                    },
                    reason => {
                        reject(reason);
                    }
                )
            })
        })
    }
    
    /**
     * Promise函數對象的race方法
     * 返回新的promise,其結果由第一個完成的promise決定
     */
    Promise.race = function(promises) {
        //返回一個promise
        return new Promise((resolve, reject) => {
            //遍歷獲取每一個primise的結果
            promises.forEach((p, index) => {
                Promise.resolve(p).then(  //Promise.resolve(p) 包裝了下p為promise,兼容數組中非promise的值
                    value => { //一旦有成功,將return變成成功
                        resolve(value);
                    },
                    reason => { //一旦有失敗,將return變成失敗
                        reject(reason);
                    }
                )
            })
        })
    }
    
    /**
     * 返回一個promise對象,它在指定的時間后才確定結果
     */
    Promise.resolveDelay = function(value, time) {
        //返回一個成功/失敗的promise
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                //value是promise
                if(value instanceof Promise) {
                    value.then(resolve, reject);
                } else { //value不是promise 
                    resolve(value);
                }
            }, time)
        })
    }
    
    /**
     * 返回一個promise對象,它在指定的時間后才失敗
     */
    Promise.rejectDelay = function(reason, time) {
        //返回一個失敗的promise
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                reject(reason);
            }, time)
        })
    }
    
    // 向外暴露Promise函數
    window.Promise = Promise
})(window)

應用舉例

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="./promise.js"></script>
        <script type="text/javascript">
            // console.log(new Promise().status)
            // const p = new Promise((resolve, reject) => {
            //     setTimeout(() =>{
            //         // resolve(1);
            //         reject(2);
            //         console.log('-----')
            //     }, 100)
            // })
            
            // p.then(
            //     value => {
            //         console.log('onResolve1()', value);
            //     },
            //     reason => {
            //         console.log('onRejected1()', reason);
            //     }
            // )
            // p.then(
            //     value => {
            //         console.log('onResolve2()', value);
            //     },
            //     reason => {
            //         console.log('onRejected2()', reason);
            //     }
            // )
            
            
            const p = new Promise((resolve, reject) => {
                setTimeout(() =>{
                    resolve(1);
                    // reject(2);    
                    console.log('-----')
                }, 100)
                
            }).then(
                value => {
                    console.log('onResolve1()', value);
                    return new Promise((resolve, reject) => reject(5))
                },
                reason => {
                    console.log('onRejected1()', reason);
                    return 4;
                }
            ).then(
                value => {
                    console.log('onResolve2()', value);
                },
                reason => {
                    console.log('onRejected2()', reason);
                    throw 6;
                }
            ).catch(
                reason => {
                    console.log('onRejected catch()', reason);
                    return new Promise(()=>{})
                }
            ).then(
                value => {
                    console.log('onResolve3()', value);
                },
                reason => {
                    console.log('onRejected3()', reason);
                    throw 6;
                }
            )
            
        </script>
    </head>
    <body>
    </body>
</html>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="./promise.js"></script>
        <script type="text/javascript">
            const p1 = Promise.resolve(2);
            const p2 = Promise.resolve(Promise.resolve(3));
            const p3 = Promise.resolve(Promise.reject(4));
            p1.then(value => {console.log('p1', value)})
            p2.then(value => {console.log('p2', value)})
            p3.catch(reason => {console.log('p3', reason)})
        </script>
    </head>
    <body>
    </body>
</html>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="./promise.js"></script>
        <script type="text/javascript">
            const p1 = Promise.resolve(2);
            const p2 = Promise.resolve(Promise.resolve(3));
            const p3 = Promise.resolve(Promise.reject(4));
            const p4 = new Promise((resolve) => {
                setTimeout(() => {
                    resolve(5);
                }, 1000)
            })
            
            const pAll = Promise.all([p4, p1, p2]);
            pAll.then(
                values => {
                    console.log('all onResolved()', values);
                },
                reasons => {
                    console.log('all onRejected()', reasons);
                }
            )
            
            // const pRace = Promise.race([p1, p2, p3]);
            // pRace.then(
            //     value => {
            //         console.log('race onResolved()', value);
            //     },
            //     reason => {
            //         console.log('race onRejected()', reason);
            //     }
            // )
            
        </script>
    </head>
    <body>
    </body>
</html>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="./promise.js"></script>
        <script type="text/javascript">
            const p1 = Promise.resolve(2);
            const p2 = Promise.resolve(Promise.resolve(3));
            const p3 = Promise.resolve(Promise.reject(4));
            const p4 = new Promise((resolve) => {
                setTimeout(() => {
                    resolve(5);
                }, 1000)
            })
            const p5 = Promise.reject(6)
            
            const pRace = Promise.race([p4, p5, p3]);
            pRace.then(
                value => {
                    console.log('race onResolved()', value);
                },
                reason => {
                    console.log('race onRejected()', reason);
                }
            )
            
            const p6 = Promise.resolveDelay(66, 3000);
            const p7 = Promise.rejectDelay(77, 2000);
            p6.then(
                value => {
                    console.log(value);
                }
            )
            p7.catch(
                reason => {
                    console.log(reason);
                }
            )
            
        </script>
    </head>
    <body>
    </body>
</html>

 

當然,還能改造為class對象

/**
 * 自定義Promise函數模塊,IIFE
 */
(function(window) {
    
    const PENDING = 'pending';
    const RESOLVED = 'resolved';
    const REJECTED = 'rejected';
    
    class Promise() {
        /**
         * Promise構造函數
         * executor: 執行器函數(同步執行)
         */
        constructor(executor) {
            const self = this;
            self.status = PENDING; //給promise對象指定status屬性,初始值為pending
            self.data = undefined; //給promise對象指定一個用於存儲結果數據的屬性
            self.callbacks = []; //每個元素的數據結構: {onResolved(){}, onReject(){}}
            
            function resolve(value) {
                //如果當前狀態不是pending,直接結束
                if(self.status !== PENDING) {
                    return;
                }
                
                //狀態為resolved
                self.status = RESOLVED;
                //保存value數據
                self.data = value;
                //如果有待執行的callback函數,立即異步執行回調函數onResolved
                if(self.callbacks.length>0) {
                    setTimeout(() => {
                        self.callbacks.forEach(callbacksObj => {
                            callbacksObj.onResolved(value);
                        })
                    })
                }
            }
            
            function reject(reason) {
                //如果當前狀態不是pending,直接結束
                if(self.status !== PENDING) {
                    return;
                }
                //狀態為rejected
                self.status = REJECTED;
                //保存value數據
                self.data = reason;
                //如果有待執行的callback函數,立即異步執行回調函數onResolved
                if(self.callbacks.length>0) {
                    setTimeout(() => {
                        self.callbacks.forEach(callbacksObj => {
                            callbacksObj.onRejected(reason);
                        })
                    })
                }
            }
            
            try {
                executor(resolve, reject);
            } catch (error) { // 如果執行器拋出異常,primose對象變成rejected狀態
                reject(error);
            }
        }
    
        /**
         * Promise原型對象的then()
         * 指定成功和失敗的回調函數
         * 返回一個新的promise對象
         */
        then(onResolved, onRejected) {
            
            //向后傳遞成功的value
            onResolved = typeof onResolved === 'function' ? onResolved : value => value
            //指定默認的失敗的回調(實現錯誤/異常穿透的關鍵點),向后傳遞失敗的reason
            onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}
            
            const self = this;
            
            //返回一個新的promise對象
            return new Promise((resolve, reject) => {
                
                //調用指定的回調函數處理,根據執行的結果改變return的promise狀態
                function handle(callback) {
                    /**
                     * 1.如果拋出異常,return的promise就會失敗,reason就是error
                     * 2.如果回調函數返回不是promise,return的promise就會成功,value就是返回的值
                     * 3.如果回調函數返回是promise,return的promise就是這個promise結果
                     */
                    try {
                        const result = callback(self.data);
                        if(result instanceof Promise) {
                            // result.then(
                            //     value => resolve(value), //當result成功時,讓return的promise也成功
                            //     reason => reject(reason) //當result失敗時,讓return的promise也失敗
                            // )
                            result.then(resolve, reject);
                        } else {
                            resolve(result);
                        }
                    } catch(error) {
                        reject(error);
                    }
                }
                
                if(self.status === PENDING) {
                    //假設當前還是pending狀態,將回調函數保存起來
                    self.callbacks.push({
                        onResolved() {
                            handle(onResolved)
                        },
                        onRejected() {
                            handle(onRejected)
                        }
                    })
                } else if(self.status === RESOLVED) { //如果當前是resolved狀態,異步執行onResolved函數並改變return的promise狀態
                    setTimeout(() => {
                        handle(onResolved);
                    })
                } else { //如果當前是rejected狀態,異步執行onRejected函數並改變return的promise狀態
                    setTimeout(() => {
                        handle(onRejected);
                    })
                }
            });
        }
        
        /**
         * Promise原型對象的catch()
         * 指定失敗的回調函數
         * 返回一個新的promise函數
         */
        catch(onRejected) {
            return this.then(undefined, onRejected);
        }
        
        // 函數對象方法,也即工具方法
        
        /**
         * Promise函數對象的resolve方法
         * 返回一個指定成功結果value的promise
         */
        static resolve = function(value) {
            //返回一個成功/失敗的promise
            return new Promise((resolve, reject) => {
                //value是promise
                if(value instanceof Promise) {
                    value.then(resolve, reject);
                } else { //value不是promise 
                    resolve(value);
                }
            })
        }
        
        /**
         * Promise函數對象的reject方法
         * 返回一個指定失敗結果reason的promise
         */
        static reject = function(reason) {
            //返回一個失敗的promise
            return new Promise((resolve, reject) => {
                reject(reason);
            })
        }
        
        /**
         * Promise函數對象的all方法
         */
        static all = function(promises) {
            // 保存所有成功的value數組
            const values = new Array(promises.length);
            // 用來保存成功的promise的數量
            let resolvedCount = 0;
            return new Promise((resolve, reject) => {
                //遍歷獲取每一個primise的結果
                promises.forEach((p, index) => {
                    Promise.resolve(p).then(
                        value => {
                            resolvedCount++; //成功的數量加1
                            values[index] = value; //p成功了,將成功的value按照順序保存到values中
                            //如果全部成功了,將return的promise改為成功
                            if(resolvedCount === promises.length) {
                                resolve(values);
                            }
                        },
                        reason => {
                            reject(reason);
                        }
                    )
                })
            })
        }
        
        /**
         * Promise函數對象的race方法
         * 返回新的promise,其結果由第一個完成的promise決定
         */
        static race = function(promises) {
            //返回一個promise
            return new Promise((resolve, reject) => {
                //遍歷獲取每一個primise的結果
                promises.forEach((p, index) => {
                    Promise.resolve(p).then(  //Promise.resolve(p) 包裝了下p為promise,兼容數組中非promise的值
                        value => { //一旦有成功,將return變成成功
                            resolve(value);
                        },
                        reason => { //一旦有失敗,將return變成失敗
                            reject(reason);
                        }
                    )
                })
            })
        }
        
        /**
         * 返回一個promise對象,它在指定的時間后才確定結果
         */
        static resolveDelay = function(value, time) {
            //返回一個成功/失敗的promise
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    //value是promise
                    if(value instanceof Promise) {
                        value.then(resolve, reject);
                    } else { //value不是promise 
                        resolve(value);
                    }
                }, time)
            })
        }
        
        /**
         * 返回一個promise對象,它在指定的時間后才失敗
         */
        static rejectDelay = function(reason, time) {
            //返回一個失敗的promise
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    reject(reason);
                }, time)
            })
        }
    }
    
    
    
    
    
    // 向外暴露Promise函數
    window.Promise = Promise
})(window)

注意點:

1、函數對象和實例對象的區別

2、同步調用和異步調用

3、Promise的幾個API


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM