乐趣区

关于javascript:Promise-代码实现

Promsie js 实现

step 1

初始化 promise 对象:

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MPromise {
    /**
     * 
     * @param {Function} fn (resolve, reject)
    */
    constructor(fn){
        // 初始状态为 pending
        this.status = PENDING;
        this.value = null;
        this.reason = null;
    }
    
    resolve(value){ }

    reject(resaon){}}

step 2

实现 resolve 和 reject 办法

    /**
     * 
     * @param {Function} fn (resolve, reject)
    */
    constructor(fn){
        // 初始状态为 pending
        this.status = PENDING;
        this.value = null;
        this.reason = null;
        try{fn(this.resolve.bind(this), this.reject.bind(this));    // 为什么须要 bind(this) ? 
            // 传入的 fn 可能是一个一般的函数,并不是箭头函数,有他本人的执行环境
        }catch(e){this.reject(e);
        }
    }
    
    resolve(value){
        // 判断状态  只有 PENDING 才能够批改状态
        if(this.status === PENDING){
            this.value = value;
            this.status = FULFILLED;
        }
    }

    reject(resaon){
        // 判断状态  只有 PENDING 才能够批改状态
        if(this.status === PENDING){
            this.resaon = resaon;
            this.status = REJECTED;
        }
    }

step 3

then 办法的实现

    then(onFulfilled, onRejected){
        // 增加兜底函数 
        const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {return value;};
        const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {throw reason;};

        // .then 的返回值整体是一个 promise
        const promise = new MPromise((resolve, reject) => {switch(this.status){
                case FULFILLED: {realOnFulfilled();
                    break;
                }
                case REJECTED: {realOnRejected();
                    break;
                }
            }
        })

        return promise;
    }

    // 工具函数 判断是否 function
    isFunction(value){return typeof value === 'function'}

须要思考到 promise 外部如果是一个异步 resolve 或者 reject 办法的状况,此时状态仍是 pending.

    // 增加两个数组,存储一部 resolve reject 办法
    FULFILLED_CALLBACK_LIST = [];
    REJECTED_CALLBACK_LIST = [];

    then(onFulfilled, onRejected){
        //...
        // .then 的返回值整体是一个 promise
        const promise = new MPromise((resolve, reject) => {switch(this.status){
                // ...
                case PENDING: {this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled);
                    this.REJECTED_CALLBACK_LIST.push(realOnRejected);
                    break;
                }
            }
        })

        return promise;
    }

那么如何去保护 FULFILLED_CALLBACK_LIST REJECTED_CALLBACK_LIST 这两个数组,到底什么时候去掉用呢?
能够应用 es6 的 get 和 set 去保护

    // 增加一个新的变量来保护状态  
    _status = PENDING;

    get status(){return this._status;}

    set status(newStatus){
        this._status = newStatus;
        switch(newStatus){
            case FULFILLED: {
                this.FULFILLED_CALLBACK_LIST.forEach(callback => {callback(this.value);
                })
                break;
            }
            case REJECTED: {
                this.REJECTED_CALLBACK_LIST.forEach(callback => {callback(this.resaon);
                })
                break;
            }
        }
    }

依据 promiseA+ 标准 onFulfilled 和 onRejected 执行的异样,promsie 须要被 rejected,并且执行后果需调用 resolvePromise 办法,所以须要对 realOnFulfilled 和 realOnRejected 函数增加 try catch 捕捉异样,调用 resolvePromise

    then(onFulfilled, onRejected){
        // ...
        // .then 的返回值整体是一个 promise
        const promise2 = new MPromise((resolve, reject) => {
            // onFulfilled 和 onRejected 执行的异样,promsie 须要被 rejected
            const fulfilledMircotask = () => {
                try{const x = realOnFulfilled(this.value);
                    this.resolvePromise(promise2, x, resolve, reject);
                }catch(e){reject(e);
                }
            }
            const rejectedMircotask = () => {
                try{const x = realOnRejected(this.resaon);
                    this.resolvePromise(promise2, x, resolve, reject);
                }catch(e){reject(e);
                }
            }

            switch(this.status){
                case FULFILLED: {fulfilledMircotask();
                    break;
                }
                case REJECTED: {rejectedMircotask();
                    break;
                }
                case PENDING: {this.FULFILLED_CALLBACK_LIST.push(fulfilledMircotask);
                    this.REJECTED_CALLBACK_LIST.push(fulfilledMircotask);
                    break;
                }
            }
        })

        return promise2;
    }

    resolvePromise(promise2, x, resolve, reject){}

promise 中 onFulfilled, onRejected 为微工作,应用 queueMicroTask 进行包裹

        const promise2 = new MPromise((resolve, reject) => {const fulfilledMircotask = () => {queueMicrotask(() => {
                    try{const x = realOnFulfilled(this.value);
                        this.resolvePromise(promise2, x, resolve, reject);
                    }catch(e){reject(e);
                    }
                })
            }
            const rejectedMircotask = () => {queueMicrotask(() => {
                    try{const x = realOnRejected(this.resaon);
                        this.resolvePromise(promise2, x, resolve, reject);
                    }catch(e){reject(e);
                    }
                })
            }
            // ...
        })    

step 4

实现 resolvePromise 办法

    resolvePromise(promise2, x, resolve, reject){
        // 如果 x promise 相等
        if(promise2 === x){return reject(new TypeError('the promise and the return value are the same'))
        }

        // 如果 x 是一个 promsie 那么让新的 promise 接口 x 的状态
        // 那继续执行 x,如果执行的时候又返回了一个 y,那么持续解析 y
        if(x instanceof MPromise){
            // 这里也是执行了 promise 须要 queueMicrotask 包裹下
            queueMicrotask(() => {
                x.then(y => {this.resolvePromise(promise2, y, resolve, reject);
                }, reject);
            })
        }else if(typeof x === 'object' && this.isFunction(x)){if(x === null){return reject(x);
            }

            let then = null;
            try{
                // 去 x.then 的值赋值给 then
                then = x.then;
            }catch(e){return reject(e);
            }

            // 如果获取的 then 是一个函数
            if(this.isFunction(then)){
                // flag 确保只被执行一次
                let called = false;
                try{
                    then.call(
                        x,
                        (y) => {if(called){return;}
                            called = true;
                            this.resolvePromise(promise2, y, resolve, reject);
                        },
                        (r) => {if(called){return;}
                            called = true;
                            reject(r);
                        }
                    )
                }catch(err){if(called){return;}
                    reject(err);
                }
            }else{resolve(x);
            }
        }else{resolve(x)
        }
    }

step 5

catch 办法实现就很简略了

    catch(onRejected){this.then(null, onRejected);
    }

step 6

除了这些 promsie 还有一些静态方法,eg resolve reject。什么是静态方法?

    static resolve(value){if(value instanceof MPromise){return value;}
        return new Promise((resolve, reject) => {resolve(value);
        })
    }

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

    // race 状态是依靠外部执行最快的那个状态
    static race(promiseList){if(!Array.isArray(promiseList)){return}
        return new Promise((resolve, reject) => {if(promiseList.length === 0){resolve();
            }else{
                promiseList.forEach(promise => {MPromise.resolve(promise).then(val => resolve(val),
                        reason => reject(reason)
                    )
                })
            }
        })
    }

    static all(promiseList){if(!Array.isArray(promiseList)){return}
        return new Promise((resolve, reject) => {if(promiseList.length === 0){resolve([]);
            }else{let count = [];
                let res = [];
                promiseList.forEach((promise, index) => {MPromise.resolve(promise).then(
                        val => {res[index] = val;
                            count++;
                            if(count === promiseList.length){    // 可否用 index === promiseList.length 来做判断  为什么?resolve(res)
                            }
                        },
                        reason => reject(reason)
                    )
                })
            }
        })
    }

    //  ...

残缺代码

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MPromise {
    // 增加两个数组,存储一部 resolve reject 办法
    FULFILLED_CALLBACK_LIST = [];
    REJECTED_CALLBACK_LIST = [];
    _status = PENDING;

    /**
     * @param {Function} fn (resolve, reject)
    */
    constructor(fn){
        // 初始状态为 pending
        this.status = PENDING;
        this.value = null;
        this.reason = null;
        try{fn(this.resolve.bind(this), this.reject.bind(this));    // 为什么须要 bind(this) ? 
            // 传入的 fn 可能是一个一般的函数,并不是箭头函数,有他本人的执行环境
        }catch(e){this.reject(e);
        }
    }
    
    resolve(value){
        // 判断状态  只有 PENDING 才能够批改状态
        if(this.status === PENDING){
            this.value = value;
            this.status = FULFILLED;
        }
    }

    reject(resaon){
        // 判断状态  只有 PENDING 才能够批改状态
        if(this.status === PENDING){
            this.resaon = resaon;
            this.status = REJECTED;
        }
    }

    get status(){return this._status;}

    set status(newStatus){
        this._status = newStatus;
        switch(newStatus){
            case FULFILLED: {
                this.FULFILLED_CALLBACK_LIST.forEach(callback => {callback(this.value);
                })
                break;
            }
            case REJECTED: {
                this.REJECTED_CALLBACK_LIST.forEach(callback => {callback(this.resaon);
                })
                break;
            }
        }
    }

    then(onFulfilled, onRejected){
        // 增加兜底函数 
        const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {return value;};
        const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {throw reason;};

        // .then 的返回值整体是一个 promise
        const promise2 = new MPromise((resolve, reject) => {
            // onFulfilled 和 onRejected 执行的异样,promsie 须要被 rejected
            const fulfilledMircotask = () => {queueMicrotask(() => {
                    try{const x = realOnFulfilled(this.value);
                        this.resolvePromise(promise2, x, resolve, reject);
                    }catch(e){reject(e);
                    }
                })
            }
            const rejectedMircotask = () => {queueMicrotask(() => {
                    try{const x = realOnRejected(this.resaon);
                        this.resolvePromise(promise2, x, resolve, reject);
                    }catch(e){reject(e);
                    }
                })
            }

            switch(this.status){
                case FULFILLED: {fulfilledMircotask();
                    break;
                }
                case REJECTED: {rejectedMircotask();
                    break;
                }
                case PENDING: {this.FULFILLED_CALLBACK_LIST.push(fulfilledMircotask);
                    this.REJECTED_CALLBACK_LIST.push(fulfilledMircotask);
                    break;
                }
            }
        })

        return promise2;
    }

    resolvePromise(promise2, x, resolve, reject){
        // 如果 x promise 相等
        if(promise2 === x){return reject(new TypeError('the promise and the return value are the same'))
        }

        // 如果 x 是一个 promsie 那么让新的 promise 接口 x 的状态
        // 那继续执行 x,如果执行的时候又返回了一个 y,那么持续解析 y
        if(x instanceof MPromise){
            // 这里也是执行了 promise 须要 queueMicrotask 包裹下
            queueMicrotask(() => {
                x.then(y => {this.resolvePromise(promise2, y, resolve, reject);
                }, reject);
            })
        }else if(typeof x === 'object' && this.isFunction(x)){if(x === null){return reject(x);
            }

            let then = null;
            try{
                // 去 x.then 的值赋值给 then
                then = x.then;
            }catch(e){return reject(e);
            }

            // 如果获取的 then 是一个函数
            if(this.isFunction(then)){
                // flag 确保只被执行一次
                let called = false;
                try{
                    then.call(
                        x,
                        (y) => {if(called){return;}
                            called = true;
                            this.resolvePromise(promise2, y, resolve, reject);
                        },
                        (r) => {if(called){return;}
                            called = true;
                            reject(r);
                        }
                    )
                }catch(err){if(called){return;}
                    reject(err);
                }
            }else{resolve(x);
            }
        }else{resolve(x)
        }
    }

    catch(onRejected){this.then(null, onRejected);
    }

    static resolve(value){if(value instanceof MPromise){return value;}
        return new Promise((resolve, reject) => {resolve(value);
        })
    }

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

    // race 状态是依靠外部执行最快的那个状态
    static race(promiseList){if(!Array.isArray(promiseList)){return}
        return new Promise((resolve, reject) => {if(promiseList.length === 0){resolve();
            }else{
                promiseList.forEach(promise => {MPromise.resolve(promise).then(val => resolve(val),
                        reason => reject(reason)
                    )
                })
            }
        })
    }

    static all(promiseList){if(!Array.isArray(promiseList)){return}
        return new Promise((resolve, reject) => {if(promiseList.length === 0){resolve([]);
            }else{let count = [];
                let res = [];
                promiseList.forEach((promise, index) => {MPromise.resolve(promise).then(
                        val => {res[index] = val;
                            count++;
                            if(count === promiseList.length){    // 可否用 index === promiseList.length 来做判断  为什么?resolve(res)
                            }
                        },
                        reason => reject(reason)
                    )
                })
            }
        })
    }

    // 工具函数 判断是否 function
    isFunction(value){return typeof value === 'function'}
}
退出移动版