一步一步的手写Promise

手写promise

写在前面(核心逻辑)

1. Promise 是一个类, 在执行这个类的时候 需要传递一个执行器进去,执行器会立即执行
2. Promise 中有三种状态,成功=>fulfilled,失败=>rejected,等待=>pending
pending --> fulfilled
pending --> rejected
状态一旦确定就不可更改
3. resolve和reject函数是用来更改状态的
resolve: fulfilled
reject: rejected
4. then方法内部做的事情就是判断状态,如果状态时成功,调用成功的回调函数,如果状态是失败,调用失败的回调函数,then方法是被定义在原型对象中的方法
5. then成功回调有一个参数 表示成功之后的值 then失败回调有一个参数 表示失败后的原因
6. 同一个promise对象下面的then方法是可以被调用多次的
7. then方法是可以被链式调用的, 后面then方法的回调函数拿到值的是上一个then方法的回调函数的返回值
8. catch只是then的一种特殊的写法 方便理解和使用
9. all 返回一个Promise,入参是数组 resolve的情况下出参也是数组 且结果顺序和调用顺序一致, 所有的值或者promise都完成才能resolve 所有要计数 ,只要有一个为reject 返回的Promise便reject
10. race 返回一个Promise, 入参是数组 那么出参根据第一个成功或者失败的参数来确定, 只要有一个resolve 或者reject 便更改返回Promise的状态

// 状态定义成常量代码会有提示并且方便复用
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
    constructor(executor) {
        executor(this.resolve, this.reject);
    }
    // promise 状态
    status = PENDING;
    // 成功之后的值
    value = undefined;
    // 失败后的原因
    reason = undefined;
    // 箭头函数目的是为了让this指向类的实例对象
    resolve = (value) => {
        // 如果状态不是等待,阻止程序向下执行
        if (this.status !== PENDING) return;
        // 将状态更改为成功
        this.status = FULFILLED;
        // 保存成功之后的值
        this.value = value;
    };
    reject = (reason) => {
        // 如果状态不是等待,阻止程序向下执行
        if (this.status !== PENDING) return;
        // 将状态更改为失败
        this.status = REJECTED;
        // 保存失败之后的原因
        this.reason = reason;
    };
    then(successCallback, failCallback) {
        // 判断状态
        if (this.status === FULFILLED) {
            successCallback(this.value);
        } else if (this.status === REJECTED) {
            failCallback(this.reason);
        }
    }
}

  • 使用自定义的promise
let promise = new MyPromise((resolve, reject) => {
    resolve("成功");
    reject("失败");
});

promise.then(
    (res) => {
        console.log(res);
    },
    (err) => {
        console.log(err);
    }
);

在Promise类中加入异步逻辑

  • 需要在Promise类中加入以下代码

在类中定义两个回调函数

 // 成功回调
    successCallback = undefined;
    // 失败回调
    failCallback = undefined;

在resolve函数内加入

// 判断成功回调是否存在,如果存在调用,成功的值必须传入
this.successCallback && this.successCallback(this.value);

在reject函数内加入

// 判断失败回调是否存在,如果存在调用,失败的原因必须传入
this.failCallback && this.failCallback(this.reason);

最后在then函数内加入

 else {
            // 当前状态是等待
            this.successCallback = successCallback;
            this.failCallback = failCallback;
        }
  • 再次使用自定义的promise
let promise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve("成功");
    }, 2000);
    reject("失败");
});

实现 then 方法多次调用添加多个处理函数

  • 收先将声明的成功回调和失败回调定义为数组
    // 成功回调
    successCallback = [];
    // 失败回调
    failCallback = [];
  • 然后在then的等待条件中(处理异步)将then的函数push到数组中
    // 当前状态是等待 异步状态存储then, then可以多个处理所以是个数组
    this.successCallback.push(successCallback);
    this.failCallback.push(failCallback);
  • 最后执行多个then中的函数,需要在resolve和reject函数内操作

将判断成功的回调改为循环数组的形式,每执行一次回调从数组中弹出

    // this.successCallback && this.successCallback(this.value);
    while (this.successCallback.length) {
        this.successCallback.shift()(this.value);
    }

失败的同理

    // this.failCallback && this.failCallback(this.reason);
    while (this.failCallback.length) {
        this.failCallback.shift()(this.reason);
    }
  • 最后执行 就会得到多个函数结果
let promise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve("成功,有几个then就会有几个成功");
    }, 2000);
});
promise.then(
    (res) => {
        console.log(res);
    },
    (err) => {
        console.log(err);
    }
);
promise.then(
    (res) => {
        console.log(res);
    },
    (err) => {
        console.log(err);
    }
);

实现 then 方法的链式调用

  • 实现then方法的链式调用,必须要让then方法自身返回一个promise对象,所以这里对then内部进行一个修改
  • 还需要对回调的返回值进行判断,判断返回值是普通值还是一个promise对象,从而进行区分处理
  • 同时将之前未处理的异常一并处理 捕获错误
    • 在执行器中捕获异常
    • 在成功/失败/等待内部进行捕获异常

定义一个判断成功回调值的类型

// 定义一个判断成功回调值的类型
function resolvePromise(promise2, x, resolve, reject) {
    // 如果then方法返回的promise和成功的回调返回的promise是同一个对象则程序报出类型错误并且不再向下进行
    if (promise2 === x) {
        return reject(
            new TypeError("Chaining cycle detected for promise #<Promise>")
        );
    }
    // 判断如果是MyPromise的实例则调用then方法,根据传入的参数来判断是执行resolve还是reject
    if (x instanceof MyPromise) {
        x.then(resolve, reject);
    } else {
        // 普通值
        resolve(x);
    }
}

then方法内经过处理后最新代码更改

     then(successCallback, failCallback) {
        // 实现then方法的链式调用,必须要让then方法自身返回一个promise对象
        let promise2 = new MyPromise((resolve, reject) => {
            // 统一异常处理逻辑
            const execFun = (fn, val) => {
                try {
                    let x = fn(val);
                    // 判断x的值是普通值还是promise对象
                    // 1.如果是普通值 直接调用resolve
                    // 2.如果是promise对象,查看promise对象的返回结果,再根据promise对象返回结果 决定调用resolve还是调用reject
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    // 调用下一个promise的reject方法,将错误信息传入
                    reject(e);
                }
            };
            // 判断状态
            if (this.status === FULFILLED) {
                // 内部无法直接拿到promise,所以需要将这一步操作变成异步操作,拿到promise2之后再调用
                queueMicrotask(() => {
                    execFun(successCallback, this.value);
                });
            } else if (this.status === REJECTED) {
                 queueMicrotask(() => {
                    execFun(failCallback, this.reason);
                });
            } else {
               // 同步将对应成功或者失败回调事件加入对应回调队列, then可以多个处理所以是个数组,push到数组中一个函数,函数内部进行异步操作来调用相对应的成功/失败的回调
                this.successCallback.push(() => {
                    execFun(successCallback, this.value);
                });
                this.failCallback.push(() => {
                    execFun(failCallback, this.reason);
                });
            }
        });
        return promise2;
    }

执行器内部异常处理代码更改

constructor(executor) {
         // 立即执行传入参数
        // 异步执行状态变更
        // 捕获执行器的异常
        try {
            executor(
                (value) => {
                    queueMicrotask(() => {
                        this.resolve(value);
                    });
                },
                (reason) => {
                    queueMicrotask(() => {
                        this.reject(reason);
                    });
                }
            );
        } catch (error) {
            this.reject(error);
        }
    }

判断成功/失败的回调代码更改—不需要这里传值,只需要执行即可(因为内部push的是一个函数,函数内部进行了赋值操作)

    // 判断成功回调是否存在,如果存在调用,成功的值必须传入
    while (this.successCallback.length) {
        this.successCallback.shift()();
    }
    // 判断失败回调是否存在,如果存在调用,失败的原因必须传入
    while (this.failCallback.length) {
        this.failCallback.shift()();
    }

将 then 方法的参数变成可选参数

执行调用相当于外部传入一个参数和返回值相同的函数

let promise = new MyPromise((resolve, reject) => {
    resolve(100);
});
  • 加入代码前
promise
    .then((value) => value)
    .then((value) => value)
    .then((res) => console.log(res));
  • 在then方法中第一句加入以下代码表示
    • 如果then方法中没有传入函数,那么需要将值一直向后传递,一直传递给有回调函数的then方法(参数必须是函数)
    successCallback = typeof successCallback === "function" ? successCallback : (value) => value;
     // 抛出一个reason表达式的异常
    failCallback = typeof failCallback === "function" ? failCallback : (reason) => { throw reason };
  • 加入代码后即可实现无参数调用then,将值一直向后传递
promise
    .then()
    .then()
    .then((res) => console.log(res));

Promise.all方法的实现

  • all是Promise的静态方法
  • all方法是解决异步并发问题的,允许按照异步代码调用的顺序得到异步调用的结果
  • all方法的返回值也是一个promise对象
  • 所有的成功才成功,只要有一个失败整个all就失败

all方法实现代码如下

    static all(array) {
        let result = [];
        let index = 0;
        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value;
                index++;
                // 因为for循环会很快结束,这一步代码主要是等待异步操作完成之后才resolve
                if (index === array.length) {
                    resolve(result);
                }
            }
            for (let i = 0; i < array.length; i++) {
                // 保存当前值
                let current = array[i];

                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(
                        (value) => {
                            addData(i, value);
                        },
                        (reason) => {
                            reject(reason);
                        }
                    );
                } else {
                    // 普通值
                    addData(i, array[i]);
                }
            }
        });
    }
  • 执行代码
function p1() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve("p1");
        }, 2000);
    });
}
function p2() {
    return new MyPromise((resolve, reject) => {
        resolve("p2");
    });
}

MyPromise.all(["a", "b", p1(), p2(), "c"]).then((res) => {
    console.log(res);
});

race方法的实现

  • race是静态方法
  • 和all不同的是只要有一个成功或者失败就返回
    static race(array) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                // 如果是MyPromise实例
                if (current instanceof MyPromise) {
                    current.then(resolve, reject);
                } else {
                    // 普通值
                    resolve(current);
                }
            }
        });
    }
  • 执行代码
MyPromise.race([p2(), p1(),'a', "b", "c"])
    .then((res) => {
        console.log(res,1);
    })
    .catch((err) => {
        console.log(err,2);
    });
    // 最先输出a 1 但是会等到p2内部的setTimeout结束程序才会结束

resolve方法的实现

  • resolve是静态方法,作用是将传入参数转变为promise对象
    • 在类中添加一个静态方法,代码如下
    static resolve(value) {
        // 如果是promise对象则直接返回
        if (value instanceof MyPromise) return value;
        // 如果是普通值则创建一个promise对象返回
        return new MyPromise((resolve) => resolve(value));
    }

finally方法的实现

  • finally无论成功还是失败callback都会执行,
  • 返回当前promise对象最终返回的结果
finally(callback) {
        return this.then(
            (value) => {
                return MyPromise.resolve(callback()).then(() => value);
            },
            (reason) => {
                return MyPromise.resolve(callback()).then(() => {
                    throw reason;
                });
            }
        );
    }

catch方法的实现

  • catch 方法用来处理当前promise对象最终状态为失败的情况(直接调用then方法即可)
    catch(failCallback) {
        // 内部也是调用的then方法,只不过没有成功的回调
        return this.then(undefined, failCallback);
    }

最终promise代码

// 状态定义成常量代码会有提示并且方便复用
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
    constructor(executor) {
        // 立即执行传入参数
        // 异步执行状态变更
        // 捕获执行器的异常
        try {
            executor(
                (value) => {
                    queueMicrotask(() => {
                        this.resolve(value);
                    });
                },
                (reason) => {
                    queueMicrotask(() => {
                        this.reject(reason);
                    });
                }
            );
        } catch (error) {
            this.reject(error);
        }
    }
    // promise 状态
    status = PENDING;
    // 成功之后的值
    value = undefined;
    // 失败后的原因
    reason = undefined;
    // 成功回调
    successCallback = [];
    // 失败回调
    failCallback = [];
    // all是静态方法
    static all(array) {
        let result = [];
        let index = 0;
        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value;
                index++;
                // 因为for循环会很快结束,这一步代码主要是等待异步操作完成之后才resolve
                if (index === array.length) {
                    resolve(result);
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {
                    // promise对象
                    current.then(
                        (value) => {
                            addData(i, value);
                        },
                        (reason) => {
                            reject(reason);
                        }
                    );
                } else {
                    // 普通值
                    addData(i, current);
                }
            }
        });
    }
    // resolve是静态方法,作用是将传入参数转变为promise对象
    static resolve(value) {
        // 如果是promise对象则直接返回
        if (value instanceof MyPromise) return value;
        // 如果是普通值则创建一个promise对象返回
        return new MyPromise((resolve) => resolve(value));
    }
    // race 是静态方法 只要有一个成功或者失败就返回
    static race(array) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                // 如果是MyPromise实例
                if (current instanceof MyPromise) {
                    current.then(resolve, reject);
                } else {
                    // 普通值
                    resolve(current);
                }
            }
        });
    }
    // 箭头函数目的是为了让this指向类的实例对象
    resolve = (value) => {
        // 如果状态不是等待,阻止程序向下执行
        if (this.status !== PENDING) return;
        // 将状态更改为成功
        this.status = FULFILLED;
        // 保存成功之后的值
        this.value = value;
        // 判断成功回调是否存在,如果存在调用,成功的值必须传入
        while (this.successCallback.length) {
            this.successCallback.shift()();
        }
    };
    reject = (reason) => {
        // 如果状态不是等待,阻止程序向下执行
        if (this.status !== PENDING) return;
        // 将状态更改为失败
        this.status = REJECTED;
        // 保存失败之后的原因
        this.reason = reason;
        // 判断失败回调是否存在,如果存在调用,失败的原因必须传入
        while (this.failCallback.length) {
            this.failCallback.shift()();
        }
    };
    then(successCallback, failCallback) {
        // 如果then方法中没有传入函数,那么需要将值一直向后传递,一直传递给有回调函数的then方法
        successCallback =
            typeof successCallback === "function"
                ? successCallback
                : (value) => value;
        failCallback =
            typeof failCallback === "function"
                ? failCallback
                : (reason) => {
                      // 抛出一个reason表达式的异常
                      throw reason;
                  };

        // 实现then方法的链式调用,必须要让then方法自身返回一个promise对象
        let promise2 = new MyPromise((resolve, reject) => {
            // 统一异常处理逻辑
            const execFun = (fn, val) => {
                try {
                    let x = fn(val);
                    // 判断x的值是普通值还是promise对象
                    // 1.如果是普通值 直接调用resolve
                    // 2.如果是promise对象,查看promise对象的返回结果,再根据promise对象返回结果 决定调用resolve还是调用reject
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    // 调用下一个promise的reject方法,将错误信息传入
                    reject(e);
                }
            };
            // 判断状态
            if (this.status === FULFILLED) {
                // 内部无法直接拿到promise,所以需要将这一步操作变成异步操作,拿到promise2之后再调用
                queueMicrotask(() => {
                    execFun(successCallback, this.value);
                });
            } else if (this.status === REJECTED) {
                queueMicrotask(() => {
                    execFun(failCallback, this.reason);
                });
            } else {
                // 同步将对应成功或者失败回调事件加入对应回调队列, then可以多个处理所以是个数组,push到数组中一个函数,函数内部进行异步操作来调用相对应的成功/失败的回调
                this.successCallback.push(() => {
                    execFun(successCallback, this.value);
                });
                this.failCallback.push(() => {
                    execFun(failCallback, this.reason);
                });
            }
        });
        return promise2;
    }
    // finally无论成功还是失败callback都会执行,并且返回当前promise对象最终返回的结果
    finally(callback) {
        return this.then(
            (value) => {
                return MyPromise.resolve(callback()).then(() => value);
            },
            (reason) => {
                return MyPromise.resolve(callback()).then(() => {
                    throw reason;
                });
            }
        );
    }
    // catch 方法用来处理当前promise对象最终状态为失败的情况(直接调用then方法即可)
    catch(failCallback) {
        // 内部也是调用的then方法,只不过没有成功的回调
        return this.then(undefined, failCallback);
    }
}

// 定义一个判断成功回调值的类型
function resolvePromise(promise2, x, resolve, reject) {
    // 如果then方法返回的promise和成功的回调返回的promise是同一个对象则程序报出类型错误并且不再向下进行
    if (promise2 === x) {
        return reject(
            new TypeError("Chaining cycle detected for promise #<Promise>")
        );
    }
    // 判断如果是MyPromise的实例则调用then方法,根据传入的参数来判断是执行resolve还是reject
    if (x instanceof MyPromise) {
        x.then(resolve, reject);
    } else {
        // 普通值
        resolve(x);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值