手写Promise核心


注意异步操作和处理异常

起步构建

状态、值、executor、resolve、reject

由于状态只改变一次,所以在resolve和reject改变状态之前要先判断当前是否为pending状态。

注意处理异常:如在executor中调用resolve或reject的时候传入未定义变量。因此需要在executor外层加上try-catch捕获异常。将报错信息作为rejected状态下promise的值。

class myPromise{
    
    
    static PENDING='pending';
    static FULLFILLED='fullfilled';
    static REJECTED='rejected';

    constructor(executor){
    
    
        this.status=myPromise.PENDING;
        this.value=null;
        try {
    
    
            executor(this.resolve.bind(this),this.reject.bind(this));
        } catch (error) {
    
    
            this.reject(error);
        }
    }
    
    resolve(value){
    
    
        if(this.status==myPromise.PENDING){
    
    
            this.status=myPromise.FULLFILLED;
            this.value=value;
        }
    }
    reject(reason){
    
    
        if(this.status==myPromise.PENDING){
    
    
            this.status=myPromise.REJECTED;
            this.value=reason;
        }
    }
}

测试:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
<script src='myPromise.js'></script>
<script>
    const p=new myPromise((resolve,reject)=>{
    
    
        resolve('成功啦');
    });
    console.log(p);
</script>
</body>
</html>

在这里插入图片描述

const p=new myPromise((resolve,reject)=>{
    
    
    resolve(a);
});
console.log(p);

在这里插入图片描述

then()、链式调用

  • 调用then的时候传入的参数可能不是函数类型,这个时候就需要自定义成功或者失败的回调。由于then具有穿透功能,因此当未传入回调时,直接返回当前value值
if(typeof onFullfilled!='function'){
    
    
    onFullfilled=()=>this.value;
}
if(typeof onRejected!='function'){
    
    
    onRejected=()=>this.value;
}
  • then方法返回值是一个新的promise

  • 异步执行(executor中的异步性、resolve、reject)、异常处理

  • 在executor中加定时器(setTimeout会将resolve放入回调队列,等其他操作顺序执行完之后才调用),调用then的时候当前promise仍是pending状态。由于每个promise都必定会经过状态为pending的时候,因此我们可以定义一个callbacks数组存储将要被调用的onFullfilled、onRejected回调,此操作放在pending状态的时候执行。当状态改变时将callbacks数组中的回调全部调出来执行,此操作在resolve()和reject()中处理。

    • 测试——没加callbacks处理的时候:
const p=new myPromise((resolve,reject)=>{
    
    
   setTimeout(()=>{
    
    
       resolve('成功');
   },100);
});
const p1=p.then(value=>{
    
    
   console.log(value);
});
console.log(p1);

在这里插入图片描述

  • 处理后:
    在这里插入图片描述
then(onFullfilled,onRejected){
    
    
        if(typeof onFullfilled!='function'){
    
    
            onFullfilled=()=>this.value;
        }
        if(typeof onRejected!='function'){
    
    
            onRejected=()=>this.value;
        }

        return new myPromise((resolve,reject)=>{
    
    
            if(this.status==myPromise.PENDING){
    
    
                this.callbacks.push({
    
    
                    Full:value=>{
    
    
                        try {
    
    
                            let result=onFullfilled(value);
                            resolve(result);
                        } catch (error) {
    
    
                            reject(error);
                        }
                    },
                    Reject:reason=>{
    
    
                        try {
    
    
                            let result=onRejected(reason);
                            resolve(result);
                        } catch (error) {
    
    
                            reject(error);
                        }
                    }
                });
            }
            if(this.status==myPromise.FULLFILLED){
    
    
                setTimeout(()=>{
    
    
                    try {
    
    
                        let result=onFullfilled(this.value);
                        resolve(result);
                    } catch (error) {
    
    
                        reject(error);
                    }
                });
            }
            if(this.status==myPromise.REJECTED){
    
    
                setTimeout(()=>{
    
    
                    try {
    
    
                        let result=onRejected(this.value);
                        resolve(result);
                    } catch (error) {
    
    
                        reject(error);
                    }
                });
            }
        });
    }

then中回调的返回值类型

无论当前promise成功与否,都返回一个成功的promise,一般情况下,成功/失败的返回值即作为新的promise的值,若返回的是promise对象(通过instanceof判断),那么将该promise对象的值作为新promise的值(此处未处理当前promise中抛出异常的情况)

处理返回promise的情况(resolve):

try {
    
    
    let result=onFullfilled(value);
    if(result instanceof myPromise){
    
    
        result.then(resolve,reject);
    }else{
    
    
        resolve(result);
    }
} catch (error) {
    
    
    reject(error);
}

测试(then穿透、resolve异步、链式、then回调返回promise):

const p=new myPromise((resolve,reject)=>{
    
    
   setTimeout(()=>{
    
    
       resolve('成功啦');
   },100);
});
p.then()
.then(value=>{
    
    
   console.log(value);
   return new myPromise((resolve,reject)=>{
    
    
       resolve('成功回调返回的promise又成功啦');
   })
})
.then(value=>{
    
    
   console.log(value);
});

console.log('输出在最后');

在这里插入图片描述

代码优化、返回约束

then返回的promise不能是then相同的peomise(可输出)
而我们目前的promise是没有这个功能的

系统Promise:

const p=new Promise((resolve,reject)=>{
    
    
    resolve('成功啦');
});
const res=p.then(value=>{
    
    
    // console.log(res);
    return res;
});

在这里插入图片描述

解决方法:
在then中的回调函数中判断返回的promise是否是当前promise,是则抛出异常,并且以上代码多处重复,可通过封装函数,将promise和回调返回结果result作为参数传递。

parse(promise,result,resolve,reject){
    
    
      if(promise==result){
    
    
          throw new TypeError('Chaining cycle detected for promise #<Promise>');
      }
      try {
    
    
          if(result instanceof myPromise){
    
    
              result.then(resolve,reject);
          }else{
    
    
              resolve(result);
          }
      } catch (error) {
    
    
          reject(error);
      }
  }

定义一个变量promise存then()中要返回的promise,并且在then末尾返回该变量

then(onFullfilled,onRejected){
    
    
    if(typeof onFullfilled!='function'){
    
    
        onFullfilled=()=>this.value;
    }
    if(typeof onRejected!='function'){
    
    
        onRejected=()=>this.value;
    }

    const promise=new myPromise((resolve,reject)=>{
    
    
        if(this.status==myPromise.PENDING){
    
    
            this.callbacks.push({
    
    
                Full:value=>{
    
    
                    this.parse(promise,onFullfilled(value),resolve,reject);
                },
                Reject:reason=>{
    
    
                    this.parse(promise,onRejected(reason),resolve,reject);
                }
            });
        }
        if(this.status==myPromise.FULLFILLED){
    
    
            setTimeout(()=>{
    
    
                this.parse(promise,onFullfilled(this.value),resolve,reject);
            });
        }
        if(this.status==myPromise.REJECTED){
    
    
            setTimeout(()=>{
    
    
                this.parse(promise,onRejected(this.value),resolve,reject);
            });
        }
    });
    return promise;
}

测试:

const p=new myPromise((resolve,reject)=>{
    
    
    resolve('成功啦');
});
const res=p.then(value=>{
    
    
    console.log(res);
    return res;
});

在这里插入图片描述

静态resolve()和reject()

静态的resolve()和reject()的实现和then()中的回调类似

static resolve(value){
    
    
    return new myPromise((resolve,reject)=>{
    
    
        if(value instanceof myPromise){
    
    
            value.then(resolve,reject);
        }else{
    
    
            resolve(value);
        }
    })
}

static reject(reason){
    
    
    return new myPromise((resolve,reject)=>{
    
    
        reject(reason);
    })
}

all(promises)

all()参数为一个promise数组,当且仅当promises数组中所有promise都成功时才返回一个成功的promise,否则为失败。

实现:遍历循环promises数组,执行每个promise的then方法,定义一个values数组存放成功的值,若values的数组大小和promises大小相等就说明所有promise都成功,此时返回一个成功的promise,其值即values数组,若有promise失败则直接调用reject()返回一个失败的promise

static all(promises){
    
    
    let 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);
            });
        });
    })
} 

测试:

  • 全部成功的情况:
const p1=myPromise.resolve('成功啦');
const p2=myPromise.resolve('又成功啦');
myPromise.all([p1,p2]).then(value=>{
    
    
    console.log(value);
},reason=>{
    
    
    console.log(reason);
});

在这里插入图片描述

  • 含失败情况
    const p1=myPromise.resolve('成功啦');
    const p2=myPromise.resolve('又成功啦');
    const p3=myPromise.reject('失败啦');
    myPromise.all([p1,p2,p3]).then(value=>{
    
    
        console.log(value);
    },reason=>{
    
    
        console.log(reason);
    });

在这里插入图片描述

race(promises)

race()的参数也是一个promise数组,该方法根据数组中最先执行完的promise返回一个新的promise,其实只需要遍历循环promises数组,每个元素执行一次then方法就好了

static race(promises){
    
    
    return new Promise((resolve,reject)=>{
    
    
        promises.forEach(promise=>{
    
    
            promise.then(value=>{
    
    
                resolve(value);
            },reason=>{
    
    
                reject(reason);
            });
        })
    })
}

测试:

const p1=new myPromise((resovle,reject)=>{
    
    
    setTimeout(()=>{
    
    
        resovle('成功啦');
    },100);
});
const p2=new myPromise((resovle,reject)=>{
    
    
    setTimeout(()=>{
    
    
        reject('失败啦');
    },200);
})

myPromise.race([p1,p2]).then(value=>{
    
    
    console.log(value);
},reason=>{
    
    
    console.log(reason);
});

在这里插入图片描述

完整代码

class myPromise{
    
    
    static PENDING='pending';
    static FULLFILLED='fullfilled';
    static REJECTED='rejected';

    constructor(executor){
    
    
        this.status=myPromise.PENDING;
        this.value=null;
        this.callbacks=[];
        try {
    
    
            executor(this.resolve.bind(this),this.reject.bind(this));
        } catch (error) {
    
    
            this.reject(error);
        }
    }
    
    resolve(value){
    
    
        if(this.status==myPromise.PENDING){
    
    
            this.status=myPromise.FULLFILLED;
            this.value=value;

            setTimeout(()=>{
    
    
                this.callbacks.map(callback=>{
    
    
                    callback.Full(value);
                })
            });
        }
    }
    reject(reason){
    
    
        if(this.status==myPromise.PENDING){
    
    
            this.status=myPromise.REJECTED;
            this.value=reason;

            setTimeout(()=>{
    
    
                this.callbacks.map(callback=>{
    
    
                    callback.Reject(reason);
                })
            });
        }
    }

    then(onFullfilled,onRejected){
    
    
        if(typeof onFullfilled!='function'){
    
    
            onFullfilled=()=>this.value;
        }
        if(typeof onRejected!='function'){
    
    
            onRejected=()=>this.value;
        }

        const promise=new myPromise((resolve,reject)=>{
    
    
            if(this.status==myPromise.PENDING){
    
    
                this.callbacks.push({
    
    
                    Full:value=>{
    
    
                        this.parse(promise,onFullfilled(value),resolve,reject);
                    },
                    Reject:reason=>{
    
    
                        this.parse(promise,onRejected(reason),resolve,reject);
                    }
                });
            }
            if(this.status==myPromise.FULLFILLED){
    
    
                setTimeout(()=>{
    
    
                    this.parse(promise,onFullfilled(this.value),resolve,reject);
                });
            }
            if(this.status==myPromise.REJECTED){
    
    
                setTimeout(()=>{
    
    
                    this.parse(promise,onRejected(this.value),resolve,reject);
                });
            }
        });
        return promise;
    }

    parse(promise,result,resolve,reject){
    
    
        if(promise==result){
    
    
            throw new TypeError('Chaining cycle detected for promise #<Promise>');
        }
        try {
    
    
            if(result instanceof myPromise){
    
    
                result.then(resolve,reject);
            }else{
    
    
                resolve(result);
            }
        } catch (error) {
    
    
            reject(error);
        }
    }
    
    static resolve(value){
    
    
        return new myPromise((resolve,reject)=>{
    
    
            if(value instanceof myPromise){
    
    
                value.then(resolve,reject);
            }else{
    
    
                resolve(value);
            }
        })
    }

    static reject(reason){
    
    
        return new myPromise((resolve,reject)=>{
    
    
            reject(reason);
        })
    }

    static all(promises){
    
    
        let 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);
                });
            });
        })
    } 

    static race(promises){
    
    
        return new Promise((resolve,reject)=>{
    
    
            promises.forEach(promise=>{
    
    
                promise.then(value=>{
    
    
                    resolve(value);
                },reason=>{
    
    
                    reject(reason);
                });
            })
        })
    }
}

猜你喜欢

转载自blog.csdn.net/Amethystlry/article/details/116593910