カスタム実現Promise

29417 ワード

Promiseは重要な知識点であり、心に銘記しなければならない.以下はカスタムで実現したPromiseである.
class MyPromise {
    //  promise 3   
    //    ,     ,     
    static PENDING = "pending";
    //       
    static FULFILLED = "fulfilled";
    //       
    static REJECTED = "rejected";
    constructor(excutor) {
        //     
        this.status = MyPromise.PENDING;
        //         
        this.callbacks = [];
        //   
        this.value = undefined;
        //
        try {
            //   excutor  ,  resolve reject this       undefined
            //     this   resolve reject,      
            excutor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
            //        reject()  
            this.reject(error);
        }
    }
    //   
    resolve(value) {
        //           
        if (this.status === MyPromise.PENDING) {
            //    ,    ,   
            this.status = MyPromise.FULFILLED;
            this.value = value;
            // setTimeout()   ,      
            setTimeout(() => {
                this.callbacks.forEach(callback => {
                    callback.onResolve(value);
                })
            })
        }
    }
    //   
    reject(reason) {
        //           
        if (this.status === MyPromise.PENDING) {
            //    ,    ,   
            this.status = MyPromise.REJECTED;
            this.value = reason;
            // setTimeout()   ,      
            setTimeout(() => {
                this.callbacks.forEach(callback => {
                    callback.onRejected(value);
                })
            })
        }
    }
    then(onResolve, onRejected) {
        //            ,          ,         
        //then      
        //  let p = new Promise((resolve,reject)=>{
        //     resolve("  ")
        // })
        // p.then().then(value=>console.log(value)) //=>  
        if (typeof onResolve !== "function") {
            onResolve = () => this.value;
        }
        if (typeof onRejected !== "function") {
            onRejected = () => this.value;
        }
        //    MyPromise  
        let promise = new MyPromise((resolve, reject) => {
            //       
            if (this.status === MyPromise.FULFILLED) {
                this.parse(promise, onResolve(this.value), resolve, reject);
            }
            if (this.status === MyPromise.REJECTED) {
                this.parse(promise, onRejected(this.value), resolve, reject);
            }
            //   resolve()  setTimeout()    
            //   let p = new Promise((resolve, reject) => {
            //     setTimeout(() => {
            //         resolve("  ")
            //     }, 100);
            // })
            // p.then(value => console.log(value)) //=>  
            //                
            if (this.status === MyPromise.PENDING) {
                this.callbacks.push({
                    onResolve: value => {
                        this.parse(promise, onResolve(value), resolve, reject);
                    },
                    onRejected: value => {
                        this.parse(promise, onRejected(value), resolve, reject);
                    }
                })
            }
        })
        return promise;
    }
    parse(promise, result, resolve, reject) {
        setTimeout(() => {
            //       ,    
            if (promise === result) {
                throw new TypeError("Chaining cycle detected");
            }
            try {
                //   return    ,    then  
                //  return   MyPromise   return   
                if (result instanceof MyPromise) {
                    //     resolve(),     reject()
                    // result.then(
                    //     value => {
                    //         resolve(value);
                    //     },
                    //     reason => {
                    //         reject(reason);
                    //     }
                    // )
                    //    
                    result.then(resolve, reject);
                } else {
                    resolve(this.value);
                }

            } catch (error) {
                //     then
                reject(error);
            }
        })
    }
    static resolve(value) {
        return new MyPromise((resolve, reject) => {
            if (value instanceof MyPromise) {
                value.then(resolve, reject);
            } else {
                resolve(value);
            }
        })
    }
    static reject(value) {
        return new MyPromise((resolve, reject) => {
            //       MyPromise  ,      
            if (value instanceof MyPromise) {
                value.then(resolve, reject);
            } else {
                reject(value);
            }
        })
    }
    //    promise         
    static all(promises) {
        const values = [];
        return new MyPromise((resolve, reject) => {
            promises.forEach(promise => {
                promise.then(
                    value => {
                        values.push(value);
                        //          
                        if (values.length === promises.length) {
                            resolve(values);
                        }
                    },
                    reason => {
                        //                
                        reject(reason);
                    }
                )
            })
        });
    }
    //    promise          promise
    static race(promises) {
        return new MyPromise((resolve, reject) => {
            promises.forEach(promise => {
                promise.then(
                    value => {
                        //        
                        resolve(value);
                    },
                    reason => {
                        //        
                        reject(reason);
                    }
                )
            })
        });
    }
}