手写Promise并且通过官方测试用例

139 阅读5分钟

前言

手写promise的学习笔记,纯粹图一乐,方便后续的复习啥的,如果有错误或者更好的方法,希望看到的大佬不吝赐教

步骤

1 了解promise规范,上一篇笔记已经更新 promiseA+规范(英文)

2 实现

3 测试 promiseA+测试工具

这一篇着重实现,顺带测试一下,部分规范在代码中也会附带的说明一下

开始

构造函数

statusMap = {
    PENDING: "pending",
    FULFILLED: "fulfilled",
    REJECTED: "rejected",
};

class Promise {
    constructor(fn) {
        this.status = statusMap.PENDING;
        this.value = undefined;
        this.reason = undefined;
        //new Promise的时候,需要传入一个方法,方法包含两个参数,用来根据执行结果改变promise的状态和value或者reason
        fn(
            (value) => {
            //因为测试用例中有一个套娃的例子,value是thenable,所以这里走promise解析的方法
              //fulfilledPromise(this,value)
                resolvePromise(this, value);
            },
            (reason) => {
                rejectedPromise(this, reason);
            }
        );
    }
    then() {}
}

改变promise状态的方法

由于状态只能从pending改变成其他状态,所以只能状态只能改变一次,所以方法中做了判断

function fulfilledPromise(promise, value) {
    if (promise.status !== statusMap.PENDING) return;
    promise.status = statusMap.FULFILLED;
    promise.value = value;
}

function rejectedPromise(promise, reason) {
    if (promise.status !== statusMap.PENDING) return;
    promise.status = statusMap.REJECTED;
    promise.reson = reason;
}
//promise 解析过程,由于会分好几种情况,最后再写
function resolvePromise(promise, x) {
    // todo
}
//后面要用到的公共方法
function isFunction(fn) {
    return (
        Object.prototype.toString.call(fn).toLocaleLowerCase() ===
        "[object function]"
    );
}

function isPromise(x) {
    return x instanceof Promise
}

function isObject(obj) {
    return (
        Object.prototype.toString.call(obj).toLocaleLowerCase() ===
        "[object object]"
    );
}

then

...部分代码省略...



function runCbs(list, value) {
    list.forEach((cb) => cb(value));
}

function fulfilledPromise(promise, value) {
    if (promise.status !== statusMap.PENDING) return;
    promise.status = statusMap.FULFILLED;
    promise.value = value;
    //改变状态时执行then里面的回调
    runCbs(promise.fulfilledCbs, value);
}

function rejectedPromise(promise, reason) {
    if (promise.status !== statusMap.PENDING) return;
    promise.status = statusMap.REJECTED;
    promise.reason = reason;
    runCbs(promise.rejectedCbs, reason);
}

class Promise {
    constructor(fn) {
        this.status = statusMap.PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.fulfilledCbs = []; //promise可以多次调用then方法,所以用数组储存then里面的fulfilled回调函数
        this.rejectedCbs = [];
        fn(
            (value) => {
                resolvePromise(this, value);
            },
            (reason) => {
                rejectedPromise(this, reason);
            }
        );
    }
    then(onFulfilled, onRejected) {
        let promise1 = this;
        let promise2 = new Promise(() => {});
        if (promise1.status === statusMap.FULFILLED) {
            //如果onFulfilled不是一个函数,则忽略
            if (!isFunction(onFulfilled)) {
                return promise1;
            }
            //then 里面的方法施异步执行,用setTimeout模拟异步
            setTimeout(() => {
                try {
                    //onRejected或者onFulfilled return了一个值X,则进入解析过程
                    let x = onFulfilled(promise1.value);
                    resolvePromise(promise2, x);
                } catch (error) {
                    rejectedPromise(promise2, error);
                }
            });
        }
        if (promise1.status === statusMap.REJECTED) {
            //如果onFulfilled不是一个函数,则忽略
            if (!isFunction(onRejected)) {
                return promise1;
            }
            setTimeout(() => {
                try {
                    let x = onRejected(promise1.reason);
                    resolvePromise(promise2, x);
                } catch (error) {
                    rejectedPromise(promise2, error);
                }
            });
        }
        //promsie的status为pending 的时候,需要等待new Promsie 时传入的参数出结果
        //然后通过传给then的回调获取结果
        if (promise1.status === statusMap.PENDING) {
            onFulfilled = isFunction(onFulfilled) ?
                onFulfilled :
                (value) => {
                    return value;
                };
            onRejected = isFunction(onRejected) ?
                onRejected :
                (error) => {
                    throw error;
                };
            //
            //promise可以多次调用then,onfulfilled和onRejected会根据promsie状态改变的时候视情况按照注册顺序执行
            promise1.fulfilledCbs.push(() => {
                setTimeout(() => {
                    try {
                        let x = onFulfilled(promise1.value);
                        resolvePromise(promise2, x);
                    } catch (error) {
                        rejectedPromise(promise2, error);
                    }
                });
            });
            promise1.rejectedCbs.push(() => {
                setTimeout(() => {
                    try {
                        let x = onRejected(promise1.reason);
                        resolvePromise(promise2, x);
                    } catch (error) {
                        rejectedPromise(promise2, error);
                    }
                });
            });
        }
        return promise2;
    }
}

promise解析

promis解析有四种情况

  • 1 如果promise和x指向同一个值
  • 2 如果x是一个promise
  • 3 如果x是一个对象或者函数
  • 4 如果x既不是一个对象也不是函数
function resolvePromise(promise, x) {
    //如果promise和x指向同一个值
    if (promise === x) {
        rejectedPromise(promise, new TypeError('cant be same'))
        return
    }
    //如果x是一个promise
    if (isPromise(x)) {
        //如果x的状态是fulfilled,则将x的value 作为promise的value,将他的状态改为fulfilled
        if (x.status === statusMap.FULFILLED) {
            fulfilledPromise(promise, x.value)
            return
        }
        if (x.status === statusMap.REJECTED) {
            rejectedPromise(promise, x.reason)
            return
        }
        if (x.status === statusMap.PENDING) {
            x.then(
                () => {
                    fulfilledPromise(promise, x.value)
                },
                () => {
                    rejectedPromise(promise, x.reason)
                }
            )
            return
        }
        return
    }
    if (isObject(x) || isFunction(x)) {
        //thenable
        let then
        let isCall = false
        try {
            then = x.then
        } catch (error) {
            rejectedPromise(promise, error)
            return
        }
        if (isFunction(then)) {
            try {
                then.call(x,
                    (y) => {
                        if (isCall) return
                        isCall = true
                        resolvePromise(promise, y)
                    },
                    (r) => {
                        if (isCall) return
                        isCall = true
                        rejectedPromise(promise, r)
                    }
                )
            } catch (error) {
                if (isCall) return
                isCall = true
                rejectedPromise(promise, error)
            }
            return
        } else {
            fulfilledPromise(promise, x)
            return
        }
    } else {
        fulfilledPromise(promise, x)
        return
    }
}

完整代码

statusMap = {
    PENDING: "pending",
    FULFILLED: "fulfilled",
    REJECTED: "rejected",
};
//将promise设置为fulfilled状态
function fulfilledPromise(promise, value) {
    //promise的状态只能改变一次,只能从pending改变为其他状态
    if (promise.status !== statusMap.PENDING) {
        return;
    }
    promise.status = statusMap.FULFILLED;
    promise.value = value;
    //改变状态时会异步执行then里面的回调
    runCbs(promise.fulfilledCbs, value);
}
//将promise设置为rejected状态
function rejectedPromise(promise, reason) {
    //promise的状态只能改变一次
    if (promise.status !== statusMap.PENDING) {
        return;
    }
    promise.status = statusMap.REJECTED;
    promise.reason = reason;
    //改变状态时会异步执行then里面的回调
    runCbs(promise.rejectedCbs, reason);
}

function isFunction(fn) {
    return (
        Object.prototype.toString.call(fn).toLocaleLowerCase() ===
        "[object function]"
    );
}

function isPromise(p) {
    return p instanceof Promise;
}

function isObject(obj) {
    return (
        Object.prototype.toString.call(obj).toLocaleLowerCase() ===
        "[object object]"
    );
}

function runCbs(cbs, val) {
    cbs.forEach((cb) => cb(val));
}

//promise 解析过程
function resolvePromise(promise, x) {
    //如果promise和x指向同一个值
    if (x === promise) {
        rejectedPromise(promise, new TypeError("cant be the same"));
        return;
    }
    //如果x是一个promise
    if (isPromise(x)) {
        if (x.status === statusMap.FULFILLED) {
            fulfilledPromise(promise, x.value);
            return;
        }
        if (x.status === statusMap.REJECTED) {
            rejectedPromise(promise, x.reason);
            return;
        }
        if (x.status === statusMap.PENDING) {
            x.then(
                () => {
                    fulfilledPromise(promise, x.value);
                },
                () => {
                    rejectedPromise(promise, x.reason);
                }
            );
            return;
        }
        return;
    }
    //如果x是一个对象或者函数(thenable)
    if (isObject(x) || isFunction(x)) {
        let then;
        let isCalled = false;
        try {
            then = x.then;
        } catch (error) {
            rejectedPromise(promise, error);
            return;
        }
        //如果then是一个函数
        if (isFunction(then)) {
            try {
                then.call(
                    x,
                    (y) => {
                        if (isCalled) return;
                        isCalled = true;
                        resolvePromise(promise, y);
                    },
                    (r) => {
                        if (isCalled) return;
                        isCalled = true;
                        rejectedPromise(promise, r);
                    }
                );
            } catch (error) {
                //如果执行过程出错,则需要看一下两个函数是否已经执行过了,
                //如果执行过了,说明promise的状态已经改变过了,所以按照规范不能再次改变,所以不错处理
                //如果没有执行过,需要把promise设置为rejected状态,他的reason是执行时返回的异常
                if (isCalled) {
                    return;
                }
                isCalled = true;
                rejectedPromise(promise, error);
            }
            return;
        } else {
            //如果then不是一个函数,则将x作为promise的值,将promise状态变成fulfilled
            fulfilledPromise(promise, x);
            return;
        }
    } else {
        //如果x不是对象也不是函数,则将x作为promise的值,将promise状态变成fulfilled
        fulfilledPromise(promise, x);
        return;
    }
}

class Promise {
    constructor(fn) {
            this.status = statusMap.PENDING;
            this.value = undefined;
            this.reason = undefined;
            this.fulfilledCbs = []; //promise可以多次调用then方法,所以用数组储存then里面的fulfilled回调函数
            this.rejectedCbs = [];
            //创建promise的时候,会传入一个函数,函数有用两个方法resolve和reject作为参数
            // let p= new Promise((resolve, reject) => {
            //   setTimeout(() => {
            //     console.log("执行");
            //     resolve("then执行");
            //   }, 2000);
            // });
            fn(
                (value) => {
                    resolvePromise(this, value);
                },
                (reason) => {
                    rejectedPromise(this, reason);
                }
            );
        }
        //要有一个then方法
    then(onFulfilled, onRejected) {
        const promise1 = this;
        //then方法会return一个promise
        const promise2 = new Promise(() => {});
        if (promise1.status === statusMap.FULFILLED) {
            if (!isFunction(onFulfilled)) {
                return promise1;
            }
            setTimeout(() => {
                try {
                    const x = onFulfilled(promise1.value);
                    //x的值会影响到新生成的promise2
                    resolvePromise(promise2, x);
                } catch (error) {
                    rejectedPromise(promise2, error);
                }
            }, 0);
        }
        if (promise1.status === statusMap.REJECTED) {
            if (!isFunction(onRejected)) {
                return promise1;
            }
            setTimeout(() => {
                try {
                    const x = onRejected(promise1.reason);
                    //x的值会影响到新生成的promise2
                    resolvePromise(promise2, x);
                } catch (error) {
                    rejectedPromise(promise2, error);
                }
            }, 0);
        }
        //如果是pending状态则需要等到promise的参数(回调函数)执行出结果
        //执行出来的结果则需要通过传给then的参数(回调函数)取得
        if (promise1.status === statusMap.PENDING) {
            onFulfilled = isFunction(onFulfilled) ?
                onFulfilled :
                (value) => {
                    return value;
                };
            onRejected = isFunction(onRejected) ?
                onRejected :
                (err) => {
                    throw err;
                };
            promise1.fulfilledCbs.push(() => {
                setTimeout(() => {
                    try {
                        const x = onFulfilled(promise1.value);
                        resolvePromise(promise2, x);
                    } catch (error) {
                        rejectedPromise(promise2, error);
                    }
                }, 0);
            });
            promise1.rejectedCbs.push(() => {
                setTimeout(() => {
                    try {
                        const x = onRejected(promise1.reason);
                        resolvePromise(promise2, x);
                    } catch (error) {
                        rejectedPromise(promise2, error);
                    }
                }, 0);
            });
        }
        return promise2;
    }
}

Promise.deferred = function() {
    const deferred = {};
    deferred.promise = new Promise((resolve, reject) => {
        deferred.resolve = resolve;
        deferred.reject = reject;
    });
    return deferred;
};
module.exports = Promise;