自定义Promise实现

Posted jerryleeplus

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义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

以上是关于自定义Promise实现的主要内容,如果未能解决你的问题,请参考以下文章

自定义Promise实现

自定义实现JavaScript中的Promise

自定义实现JavaScript中的Promise

实现一个自定义Promise

实现一个自定义Promise

VS Code中自定义Emmet代码片段