高级开发者必须掌握的手写Promise终结篇(附源码)

171 阅读5分钟

前面3篇文章深入讲解了 Promise A+ 规范之基本介绍 Promise A+规范之Promise解决过程高级开发者必须掌握的手写Promise(一),建议看这篇之前必须去把上面三篇文章看懂,否则很难看懂此文~

本篇文章主要是实现Promise A+规范之Promise解决过程~

一、Promise 解决过程规范

Promise 解决过程 是一个抽象的操作,其需输入一个 promise 和一个值,我们表示为 [[Resolve]](promise, x),如果 x 有 then 方法且看上去像一个 Promise ,解决程序即尝试使 promise 接受 x 的状态;否则其用 x 的值来执行 promise 。

这种 thenable 的特性使得 Promise 的实现更具有通用性:只要其暴露出一个遵循 Promise/A+ 协议的 then 方法即可;这同时也使遵循 Promise/A+ 规范的实现可以与那些不太规范但可用的实现能良好共存。

运行 [[Resolve]](promise, x) 需遵循以下步骤:

x 与 promise 相等

如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise

x 为 Promise

如果 x 为 Promise ,则使 promise 接受 x 的状态 注4

  • 如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
  • 如果 x 处于执行态,用相同的值执行 promise
  • 如果 x 处于拒绝态,用相同的据因拒绝 promise

x 为对象或函数

如果 x 为对象或者函数:

  • 把 x.then 赋值给 then 注5

  • 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise

  • 如果 then 是函数,将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise:

    • 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)

    • 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise

    • 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用

    • 如果调用 then 方法抛出了异常 e

      • 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
      • 否则以 e 为据因拒绝 promise
    • 如果 then 不是函数,以 x 为参数执行 promise

  • 如果 x 不为对象或者函数,以 x 为参数执行 promise

二、主要功能讲解

  • then返回一个Promise对象
promise2 = promise1.then(onFulfilled, onRejected);
  • onFulfilled可能返回普通值、promise对象等

  • onRejected可能返回普通值、promise对象等

  • catch的实现

三、 具体实现

(1)then返回一个Promise对象

then(onFulfilled, onRejected) {
    let promise2 = new localPromise((resolve, reject) => {
        if(this.state === STATUS.FULFILLED) {
            let x = onFulfilled(this.value)
        }
        //以下代码省略......
    });
    return promise2;
}

(2)实现Promise 解决过程

then(onFulfilled, onRejected) {
    let promise2 =  new localPromise((resolve, reject) => {
        if(this.state === STATUS.FULFILLED) {
            let x = onFulfilled(this.value)
            setTimeout(() => { //使用异步代码的原因是确保promise2必须初始化完成
                resolvePromise(promise2, x, resolve, reject); //Promise 解决过程
            }, 0)
        }

        if(this.state === STATUS.REJECTED) {
            let x = onFulfilled(this.reason)
            setTimeout(() => {
                resolvePromise(promise2, x, resolve, reject);  //Promise 解决过程
            }, 0)
        }

        if (onFulfilled && isFunction(onFulfilled)) {
            //将onFulfilled回调存储在onFulfilledCallbacks中
            this.onFulfilledCallbacks.push(() => {
                let x = onFulfilled(this.value); 
                resolvePromise(promise2, x, resolve, reject); //Promise 解决过程
            });
        }

        if (onRejected && isFunction(onRejected)) {
            //将onFulfilled回调存储在onFulfilledCallbacks中
            this.onRejectedCallbacks.push(() => {
                let x = onRejected(this.reason);
                resolvePromise(promise2, x, resolve, reject); //Promise 解决过程
            });
        }
    });

    return promise2;

}

(3)resolvePromise(promise2, x, resolve, reject)

function resolvePromise(promise2, x, resolve, reject) {
    if (x === promise2) {//如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise
        reject(new TypeError("Chaining cycle detected for promise #<localPromise>"));
    } if (x instanceof localPromise && x != promise2) { //如果 x 为 Promise ,则使 promise 接受 x 的状态
        try {
            // resolve(`x instanceof localPromise`);
            x.then(value => {
                resolve(value); 
            }, reject => {
                reject(reject);
            });

        } catch (e) {
            console.log(`x.then`, e)
        }
    } if(x instanceof Object || typeof x === 'function') { //x 为对象或函数
        try {
            then = x.then; //把 x.then 赋值给 then
            if(typeof then === 'function') {
            //如果 `then` 是函数,将 `x` 作为函数的作用域 `this` 调用之。
            //传递两个回调函数作为参数
                then.call(x, (y) => {
                    //如果 `resolvePromise` 以值 `y` 为参数被调用,则运行 `[[Resolve]](promise, y)`
                    resolvePromise(promise2, y, resolve, reject);
                }, (r) => {
                    //如果 `rejectPromise` 以据因 `r` 为参数被调用,则以据因 `r` 拒绝 `promise`
                    reject(y)
                })
            } else { //如果 `then` 不是函数,以 `x` 为参数执行 `promise`
                resolve(x); 
            }
        } catch (e) {
            reject(e); //如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
        }

    } else {//如果 `x` 不为对象或者函数,以 `x` 为参数执行 `promise`
        resolve(x);
    }
}

(4)catch的实现

catch其实就是then(null, onRejected)

catch(errorCallbacks) {
   return this.then(null, errorCallbacks);
}

对onFulfilled, onRejected非函数的处理

  • 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
  • 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => { value }
onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason}

四、完整源码

//状态枚举
const STATUS = {
    PENDING: 'PENDING',
    FULFILLED: 'FULFILLED',
    REJECTED: 'REJECTED'
}

class localPromise {
    constructor(executor) {
        //最初始状态
        this.state = STATUS.PENDING;
        this.value = undefined;  //值或者终值
        this.reason = undefined; //拒因或者失败原因
        //存储异步回调,为啥用数组,是因为promise实例可以多次调then,
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];

        const resolve = function (value) { // resolve函数,功能是扭转状态为fulFilled&设置终值
            if (this.state === STATUS.PENDING) {
                this.state = STATUS.FULFILLED;
                this.value = value;
                console.log('执行resolve', value);
                this.onFulfilledCallbacks.forEach(cb => {
                    cb();
                });
            }
        }.bind(this)

        const reject = function (reason) { // reject函数,功能是扭转状态为rejected&设置拒因
            if (this.state === STATUS.PENDING) {
                this.state = STATUS.REJECTED;
                this.reason = reason;
                console.log('执行reject', reason);
                this.onRejectedCallbacks.forEach(cb => {
                    cb();
                });
            }
        }.bind(this)

        try { //捕获异常,并执行reject,保存错误的时候扭转状态为rejected&设置拒因
            executor(resolve, reject);
        } catch (e) {
            reject(e);
        }
    }
    //接受两个参数 onFulfilled和onRejected
    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => { value }
        onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason}
        let promise2 =  new localPromise((resolve, reject) => {
            console.log(this.state);
            if(this.state === STATUS.FULFILLED) {
                let x = onFulfilled(this.value)
                setTimeout(() => {
                    resolvePromise(promise2, x, resolve, reject);
                }, 0)
            }

            if(this.state === STATUS.REJECTED) {
                let x = onFulfilled(this.reason)
                resolvePromise(promise2, x, resolve, reject);
            }

            if (this.state === STATUS.PENDING) {
                //将onFulfilled回调存储在onFulfilledCallbacks中
                this.onFulfilledCallbacks.push(() => {
                    let x = onFulfilled(this.value);
                    resolvePromise(promise2, x, resolve, reject);
                });
            }
        });

        return promise2;

    }

    catch(errorCallback) {
        return this.then(null, errorCallback);
    }
}

function isFunction(value) {
    return typeof value === 'function' && typeof value.nodeType !== 'number';
}

function resolvePromise(promise2, x, resolve, reject) {
    if (x === promise2) {//如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise
        reject(new TypeError("Chaining cycle detected for promise #<localPromise>"));
    } if (x instanceof localPromise && x != promise2) { //如果 x 为 Promise ,则使 promise 接受 x 的状态
        try {
            // resolve(`x instanceof localPromise`);
            x.then(value => {
                resolve(value); 
            }, reject => {
                reject(reject);
            });

        } catch (e) {
            console.log(`x.then`, e)
        }
    } if(x instanceof Object || typeof x === 'function') { //x 为对象或函数
        let then;
        try {
            then = x.then; //把 x.then 赋值给 then
            if(typeof then === 'function') {//如果 then 是函数,
                then.call(x, (y) => {
                    resolvePromise(promise2, y, resolve, reject);
                }, (r) => {
                    reject(y)
                })
            } else {
                resolve(x);
            }
        } catch (e) {
            reject(e); //如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
        }
    } else {
        resolve(x);
    }
}