手写Promise

35 阅读2分钟

手写Promise(构造函数)

//定义状态
const PENDING_STATE = "pending";
const FULFILLED_STATE = "fulfilled";
const REJECTED_STATE = "rejected";

const isFunction = function (fn) {
    return typeof fn === "function";
};

const isObject = function (value) {
    return value && typeof value === "object";
};

function MyPromise(fn) {
    if (!this || this.constructor !== MyPromise) {
        throw new TypeError("Promise must be called with new");
    }
    // 1.2 判断参数fun是否是一个函数
    if (!isFunction(fn)) {
        throw new TypeError("Promise constructor's argument must be a function");
    }
    //定义基本属性
    this.state = PENDING_STATE;
    this.value = void 0;
    this.onFulfilledCallbacks = [] // 保存完成回调
    this.onRejectedCallbacks = [] // 保存拒绝回调

    const resolve = (value) => {
        resolutionProcedure(this, value)
    }

    const resolutionProcedure = function (promise, v) {
        //判断v是否是promise自身
        if (v === promise) {
            return reject(new TypeError("Promise can not resolved with it self"))
        }
        //判断v是否是promise
        if (v instanceof MyPromise) {
            return v.then(resolve, reject)
        }
        //判断v是否是一个对象或函数
        if (isObject(v) || isFunction(v)) {
            let called = false
            try {
                let then = v.then
                if (isFunction(then)) {
                    then.call(
                        v,
                        (y) => {
                            if (called) {
                                return
                            }
                            called = true
                            resolutionProcedure(promise, y)
                        },
                        (error) => {
                            if (called) {
                                return
                            }
                            called = true
                            reject(error);
                        }
                    )
                    return
                }
            } catch (error) {
                if (called) {
                    return;
                }
                called = true;
                reject(error);
            }
        }
        if (promise.state === PENDING_STATE) {
            promise.state = FULFILLED_STATE
            promise.value = v
            promise.onFulfilledCallbacks.forEach((callback) => callback())
        }
    }

    const reject = (reason) => {
        if (this.state === PENDING_STATE) {
            this.state = REJECTED_STATE
            this.value = reason
            this.onRejectedCallbacks.forEach((callback) => callback())
        }
    }

    //  执行fn函数
    try {
        fn(resolve, reject);
    } catch (error) {
        reject(error);
    }
}

MyPromise.prototype.then = function (onFulfilled, onRejected) {
    onFulfilled = isFunction(onFulfilled) ? onFulfilled : (value) => value
    onRejected = isFunction(onRejected) ? onRejected : (error) => { throw error }
    //返回新的promise实例
    let newPromise = new MyPromise((resolve, reject) => {
        //包装onFulfilled和onRejected为异步函数
        let wrapOnFulfilled = () => {
            setTimeout(() => {
                try {
                    let v = onFulfilled(this.value)
                    resolve(v)
                } catch (error) {
                    reject(error)
                }
            }, 0)
        }
        let wrapOnRejected = () => {
            setTimeout(() => {
                try {
                    let v = onRejected(this.value)
                    resolve(v)
                } catch (error) {
                    reject(error)
                }
            }, 0)
        }
        if (this.state === FULFILLED_STATE) {
            wrapOnFulfilled()
        } else if (this.state === REJECTED_STATE) {
            wrapOnRejected()
        } else {
            this.onFulfilledCallbacks.push(wrapOnFulfilled);
            this.onRejectedCallbacks.push(wrapOnRejected);
        }
    })
    return newPromise
}

MyPromise.prototype.catch = function (callback) {
    return this.then(null, callback);
};

MyPromise.prototype.finally = function (callback) {
    return this.then(
        (data) => {
            callback();
            return data;
        },
        (error) => {
            callback();
            throw error;
        }
    );
};

MyPromise.resolve = function (value) {
    return value instanceof MyPromise
        ? value
        : new MyPromise((resolve) => resolve(value));
};

MyPromise.reject = function (reason) {
    return new MyPromise((resolve, reject) => reject(reason));
};

MyPromise.race = function (promises) {
    return new MyPromise((resolve, reject) => {
        promises.forEach((promise) => {
            MyPromise.resolve(promise).then(resolve, reject);
        });
    });
};
MyPromise.all = function (promises) {
    return new MyPromise((resolve, reject) => {
        if (!promises.length) {
            resolve([]);
        }

        let result = [];
        let resolvedPro = 0;
        for (let index = 0, length = promises.length; index < length; index++) {
            MyPromise.resolve(promises[index]).then(
                (data) => {
                    // 注意,这里要用index赋值,而不是push。因为要保持返回值和接收到的promise的位置一致性。
                    result[index] = data;
                    if (++resolvedPro === length) {
                        resolve(result);
                    }
                },
                (error) => {
                    reject(error);
                }
            );
        }
    });
};
MyPromise.allSettled = function (promises) {
    return new MyPromise((resolve, reject) => {
        if (!promises.length) {
            resolve([]);
        }

        let result = [];
        let resolvedPro = 0;
        for (let index = 0, length = promises.length; index < length; index++) {
            MyPromise.resolve(promises[index])
                .then((data) => {
                    // 注意,这里要用index赋值,而不是push。因为要保持返回值和接收到的promise的位置一致性。
                    result[index] = {
                        status: FULFILLED_STATE,
                        value: data,
                    };
                    if (++resolvedPro === length) {
                        resolve(result);
                    }
                })
                .catch((error) => {
                    result[index] = {
                        status: REJECTED_STATE,
                        reason: error,
                    };
                    if (++resolvedPro === length) {
                        resolve(result);
                    }
                });
        }
    });
};

module.exports = MyPromise;