手撕Promise源码

208 阅读2分钟

最近一直很困惑Promise的许多细节点,故理了一下思绪,手撕Promise源码,有注释,已测试通过

/*
尽可能还原 Promise 中的每一个 API
*/
const PENDING='pending';  //状态:等待中
const FULFILLED='fulfilled';  //状态:成功
const REJECTED='rejected';   //状态:失败
class MyPromise {
    constructor(executor) { //增加执行器并且立即执行
        try{
            executor(this.resolve,this.reject)
        }catch (e) {
            this.reject(e) //捕捉执行器错误,并且在then里面的错误错误回调函数抛出
        }
    }
    status=PENDING;   //状态默认等待中
    value=undefined;  //resolve传递的值,保存到类上
    reason=undefined;  //reject传递的值,保存到类上
    successCallback=[];  //成功回调函数
    failCallback=[];   //失败回调函数

    resolve=value=>{
       if(this.status!==PENDING) return //状态一旦改变,不是PENDING则不可再更改
        this.status=FULFILLED;
       this.value=value;  //状态成功的VALUE暂时存储
        while (this.successCallback.length){
            this.successCallback.shift()(); //循环调用数组内的方法
        }
    }

    reject=reason=>{
        if(this.status!==PENDING) return //状态一旦改变,不是PENDING则不可再更改
        this.status=REJECTED;
        this.reason=reason; //状态失败的REASON暂时存储
        while (this.failCallback.length) this.failCallback.shift()(); //循环调用数组内的方法
    }

    then(successCallback,failCallback){
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => {throw reason}
        let promise = new MyPromise((resolve,reject)=>{
            if(this.status===FULFILLED){
                setTimeout(()=>{
                    promiseFunc({fn:successCallback,promise,resolve,reject,value:this.value})
                },0);
            }else if(this.status===REJECTED){
                setTimeout(()=>{
                    promiseFunc({fn:failCallback,promise,resolve,reject,value:this.reason})
                },0);
            }else{
                //异步函数时状态依然为pending时,把成功回调函数和失败回调函数暂时存储
                this.successCallback.push(()=>{
                    setTimeout(()=>{
                        promiseFunc({fn:successCallback,promise,resolve,reject,value:this.value})
                    },0);
                });
                this.failCallback.push(()=>{
                    setTimeout(()=>{
                        promiseFunc({fn:failCallback,promise,resolve,reject,value:this.reason})
                    },0);
                });
            }
        });
        return promise;  //then方法最后返回MyPromise实例
    }

    catch(failCallback){
        return this.then(undefined,failCallback);
    }

    finally(callback){
        //通过this.then方法调用callback,无论状态是否成功
        return this.then((value)=>{ //finally方法后面可以调用then方法,故返回MyPromise对象
             return MyPromise.resolve(callback()).then(()=>value) //等待callback调用完毕才返回成功或者失败后的值
        },(reason)=>{
            return MyPromise.resolve(callback()).then(()=>{throw reason})
        })
    }

    static all(arr){ //all方法最终返回promise对象,后面可以调用then
        const promise2=new MyPromise((resolve,reject)=>{
            let result=[];
            let index=0;
            const addResult=(key,value)=>{
                result[key]=value;  //不可用result.push方法,顺序会乱
                index++
                if(index===arr.length){
                    resolve(result) //数组内元素执行完毕才传到then里面
                }
            }
            for(let i=0;i<arr.length;i++){
                let current=arr[i];
                if(current instanceof MyPromise){
                    //是MyPromise对象则通过.then拿到value然后丢到result里面
                    current.then((v)=>{addResult(i,v)},(r)=>{reject(r)});
                }else{
                    addResult(i,current)  //不是MyPromise对象直接丢到result里面
                }
            }
        });
        return promise2;
    }

    static resolve(value){
        if(value instanceof MyPromise) return value;  //普通数值直接返回
        //MyPromise对象直接返回新的MyPromise对象,并且把value传给then方法里面的成功回调函数
        return new MyPromise((resolve)=>{
            resolve(value);
        })
    }
}

//then方法里面的promise对象立即执行的部分
const promiseFunc=({fn,promise,resolve,reject,value})=>{
        try{
            const x=fn(value)  //调用resolve函数之后的值塞入成功回调函数内
            resolvePromise(promise,x,resolve,reject)
        }catch (e) {
            reject(e); //捕捉成功回调函数错误,并且在下一个then里面的错误回调函数抛出
        }
}
const resolvePromise=(promise,x,resolve,reject)=>{
    if(promise===x){
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    //x可以是在上一个then里面成功回调函数的返回值,也可以是失败回调函数的返回值
     if(x instanceof MyPromise){
         x.then(resolve,reject)
     }else{
         resolve(x)
     }
}
module.exports=MyPromise;