Promise A+ 规范

1,040 阅读4分钟

图示

PromiseA+规范.png

代码

    //定义三种状态
    const PENDING = 'pending';
    const FULFILLED = 'fulfilled';
    const REJECTED = 'rejected';
    //平常用 promise 都是通过new 关键字来 new Promise(),所以应该用构造函数或者 class 实现
    class MPromise{
        /**如果在异步情况下,我们要先拿到所有 callback,然后才能在某个时机去执行,这里建立两个数组用来存储成功和失败的回调,
        调用 then 的时候, 如果还是 pending 就存入数组 */
        FULFILLED_CALLBACK_LIST = [];
        REJECTED_CALLBACK_LIST = [];
        _status = PENDING;
        
        //入参是一个函数,函数接收 resolve 和 reject 两个参数
        //注意在初始化 promise 的时候,就用执行这个函数, 并且有任何报错都要通过 reject 跑出去
        constructor(fn){
            //设置初始状态为 pending
            this.status = PENDING;
            this.value = null;
            this.reason = null;
            try{
                fn(this.resolve.bind(this), this.reject.bind(this));
            } catch(e){
                this.rejected(e);
            }
        }
        
        /** 在status 发生变化的时候,就执行所有回调.这里咱们用的 es6 的 getter 和 setter,更符合语义 */
        get status(){
            return this._status;
        }
        
        set status(newStatus){
            this._status = newStatus;
            switch (newStatus){
                case FUFILLED:
                    this.FULFILLED_CALLBACK_LIST.forEach(callback=>{
                        callback(this.value)
                    })
                    break;
                case REJECTED:
                    this.RECJECTED_CALLBACK_LIST.forEach(callback=>{
                        callback(this.reason)
                    })
                    break;
            }
        }
        
        //根据规范,resolve()和 reject()这两个方法是要改 status的,从 pending 态改到 fulfilled/rejected 态
        resolve(value){
            if(this.status === PENDING){
                this.value = value;
                this.status = FULFILLED;
            }
        }
        
        reject(reason){
            if(this.status === PENDING){
                this.reason = reason;
                this.status = REJECTED;
            }
        }
        
        //接收两个参数 onFulfilled, onRedjected
        then(onFulfilled, onRejected){
        
            //检查处理参数,如果不是 function,就忽略. 这个忽略指的是原样返回 value/reason
            
            //如果onFulfilled不是函数,且 promise1 成功执行,promise2 必须成功执行并返回相同的值
            const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value=>value
            //如果onRejected不是函数,且 promise1 拒绝执行,promise2 必须拒绝执行并返回相同的拒因
            const realOnRejected = this.isFunction(onRejected) ? onRejected : reason=>reason
            
            //then的返回值是一个 promise, 如果onFulfilled,onRedjected抛出一个异常 e, 则
            promise2 必须拒绝执行, 并返回拒因e
            const promise2 = new MPromise((resolve, reject)=>{
                //规范中提到, onFulfilled 应该是微任务,所以用 queueMircotask调用
                const fulfilledMicrotask=()=>{
                    queueMircotask(()=>{
                        try{
                            const x = realOnFulfilled(this.value);
                            //如果 onFulfilled 返回一个值 x,则运行resolvePromise
                            this.resolvePromise(promise2, x, resolve, reject);
                        }catch (e){
                            reject(e)
                        }
                    })
                };
                //规范中提到, onRejected 应该是微任务,所以用 queueMircotask调用
                const rejectedMicrotask=()=>{
                    queueMicrotask(()=>{
                        try{
                            const x = realOnRejected(this.reason);
                            //如果 onRejected 返回一个值 x,则运行resolvePromise
                            this.resolvePromise(promise2, x, resolve, reject);
                        } catch(e){
                            reject(e)
                        }
                    })
                };
                //根据当前 promise 的状态,调用不同的函数
                switch(this.status){
                    case FULFILLED: 
                        fulfilledMicrotask()
                        break;
                    case REJECTED:
                        rejectedMicrotask()
                        break;
                    case PENDING:
                        this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
                        this.REJECTED_CALLBACK_LIST.push(rejectedMicriotask)
                }
            })
            return promise2
        }
        
        catch(onRejected){
            return this.then(null, onRejected);
        }
        
        isFunctions(param){
            return typeof param === 'function';
        }
        
        resolvePromise(promise2, x, resolve, reject){
            //如果newPromise 和 x 只想同一对象, 以 TypeError 为拒因执行 newPromise
            //这是为了防止死循环
            if(promise2 === x){
                return reject(new TypeError('The Promise and the return value are the same'));
            }
            
            if(x instanceof MPromise){
                //如果 x 为 Promise, 则是 newPromise 接受 x 的状态
                //也就是继续执行 x,如果执行的时候拿到一个 y,还要继续解析 y
                queueMicrotask(()=>{
                    x.then((y)=>{
                        this.resolvePromise(promise2, y, resolve, reject);
                    },reject);
                })
            }else if (typeof x === 'object' || this.isFunction(x)) {
                //如果 x 为对象或者函数
                if(x === null){
                    // null 也会被判为对象
                    return resolve(x)
                }
                
                let then = null;
                
                try{
                    //把 x.then 赋值给 then
                    then = x.then;
                } catch (error){
                    //如果取 x.then的值抛出错误 e,则以 e 为拒因拒绝 promise
                    return reject(error);
                }
                
                //如果 then 是函数
                if(this.isFunction(then)){
                    let called = false;
                    //将 x 作为函数的作用域 this 调用
                    //传递两个回调函数作为参数, 第一个参数叫做 resolvePromise,第二个参数叫做 rejectPromise
                    try{
                        then.call(
                            x,
                            //如果 resolvePromise 以值 y 为参数调用, 则运行 resolvePromise
                            (y)=>{
                            //需要一个变量 called 来保证只调用一次.
                                if(called) return;
                                called = true;
                                this.resolvePromise(promise2, y, resolve, reject);                               
                             },
                            //如果 rejectPromise 以拒因r 为参数被调用,则以拒因 r 拒绝 promise
                            (r)=>{
                                if(called) return;
                                called = true;
                                reject(r)
                             }
                        )
                    } catch(error){
                        //如果调用 then 方法抛出了异常 e
                        if(called) return;
                        //否则以 e 为拒因拒绝 promise
                        reject(error)
                    }
                } else{
                    //如果 then 不是函数,以 x 为参数执行 promise
                    resolve(x)
                }
            } else{
                //如果 x 部位对象或者函数, 以 x 为参数执行 promise
                resolve(x);
            }
        }
        //将现有对象转为Promise对象,如果 Promise.resolve 方法的参数,不是具有 then 方法的对象(又称 thenable 对象),则返回一个新的 Promise 对象,且它的状态为fulfilled。注意这是一个静态方法, 因为咱们是通过Promise.resolve调用的, 而不是通过实例去调用的.
        static resolve(value){
            if(value instanceof MPromise){
                return value
            }
            
            return newPromise((resolve)=>{
                resolve(value)
            })
        }
        //返回一个新的Promise实例,该实例的状态为rejected。Promise.reject方法的参数reason,会被传递给实例的回调函数。
        static reject(reason){
            return new MPromise((resolve, reject)=>{
                reject(reason)
            })
        }
        `const p = Promise.race([p1,p2,p3])`
        //该方法是将多个 Promise 实例,包装成一个新的 Promise 实例。只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
        static race(promiseList){
            return newMPromise((resolve, reject)=>{
                const length = promiseList.length;
                
                if(length === 0){
                    return resolve()
                }else {
                    for (let i = 0;i<length;i++) {
                        MPromise.resolve(promiseList[i]).then(
                            (value)=>{
                                return resolve(value)
                            }
                            (reason)=>{
                                return reject(reason)
                            }
                        )
                    }
                }
            })
        }
    }