手撕Promise以及相关方法

96 阅读2分钟

封装Promise需要注意的问题:

  1. 一个promise对象可能有多个then,catch回调,确定状态以后需要遍历所有的回调函数进行执行。
  2. then或catch回调可能在定时器中添加,如果此时确定了状态,则直接执行即可。
  3. 实现then,catch的连续调用,则在then中没有传入onRejected回调时,自定义onRejected回调,将error抛出,交给下面的catch执行。
//状态常量
const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";

//封装try/catch函数,用于执行onFulfilled或onRejected
function TryWitchCatchFn(exefn, value, resolve, reject) {
  try {
    const result = exefn(value);
    resolve(result);
  } catch (error) {
    reject(error);
  }
}

//封装Promise类
class LzPromise {
  //传入exector回调函数
  constructor(exector) {
    this.status = PROMISE_STATUS_PENDING;
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledFns = [];
    this.onRejectedFns = [];
    const resolve = (value) => {
      if (this.status == PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          //执行微任务之前要判断状态时pending
          if (this.status !== PROMISE_STATUS_PENDING) return;
          this.status = PROMISE_STATUS_FULFILLED;
          this.value = value;
          this.onFulfilledFns.forEach((fn) => {
            fn();
          });
        });
      }
    };

    const reject = (reason) => {
      if (this.status == PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          //执行微任务之前要判断状态时pending
          if (this.status !== PROMISE_STATUS_PENDING) return;
          this.status = PROMISE_STATUS_REJECTED;
          this.reason = reason;
          this.onRejectedFns.forEach((fn) => {
            fn();
          });
        });
      }
    };

    //接受传入的两个回调函数参数
    try {
      exector(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    //如果then没有传入onRejected函数,则将错误抛出,交给cath方法处理
    onRejected =
      onRejected ||
      ((err) => {
        throw err;
      });

    onFulfilled =
      onFulfilled ||
      ((value) => {
        return value;
      });

    //默认返回一个Promise对象
    return new LzPromise((resolve, reject) => {
      //如果状态已经确定
      //如,在定时器中添加then(),那么此时状态已经确定,执行执行回调即可
      if (this.status === PROMISE_STATUS_FULFILLED) {
        TryWitchCatchFn(onFulfilled, this.value, resolve, reject);
      }
      //如果有状态,直接执行
      if (this.status === PROMISE_STATUS_REJECTED) {
        TryWitchCatchFn(onFulfilled, this.reason, resolve, reject);
      }
      //如果为Pending状态,则添加到数组当中
      if (this.status === PROMISE_STATUS_PENDING) {
        this.onFulfilledFns.push(() => {
          TryWitchCatchFn(onFulfilled, this.value, resolve, reject);
        });
        this.onRejectedFns.push(() => {
          TryWitchCatchFn(onRejected, this.reason, resolve, reject);
        });
      }
    });
  }

  catch(onRejected) {
    return this.then(undefined, onRejected);
  }

  finally(onFinally) {
    this.then(
      () => {
        onFinally();
      },
      (err) => {
        onFinally();
      }
    );
  }

  static resolve(value) {
    return new LzPromise((resolve, reject) => {
      resolve(value);
    });
  }

  static reject(value) {
    return new LzPromise((resolve, reject) => {
      reject(value);
    });
  }

  static all(promises) {
    return new LzPromise((resolve, reject) => {
      let values = [];
      promises.forEach((promise) => {
        promise.then(
          (res) => {
            values.push(res);
            //所有的promise都返回结果再执行resolve
            if (values.length === promises.length) {
              resolve(values);
            }
          },
          (err) => {
            //有err直接返回
            reject(err);
          }
        );
      });
    });
  }

  static allSettled(promises) {
    return new LzPromise((resolve, reject) => {
      let resultOjb = [];
      promises.forEach((promise) => {
        promise.then(
          (res) => {
            resultOjb.push({status: PROMISE_STATUS_FULFILLED, value: res});
            if (resultOjb.length === promises.length) {
              resolve(resultOjb);
            }
          },
          (err) => {
            resultOjb.push({status: PROMISE_STATUS_REJECTED, value: err});
            if (resultOjb.length === promises.length) {
              resolve(resultOjb);
            }
          }
        );
      });
    });
  }
  //只要有一个返回结果就结束,不管是fulfiled,还是rejected状态
  static race(promises) {
    return new LzPromise((resolve, reject) => {
      promises.forEach((promise) => {
        promise.then(
          (res) => {
            resolve(res);
          },
          (err) => {
            reject(err);
          }
        );
      });
    });
  }
  //等到以fulfiled结果后才返回,所有都是rejected时,抛出固定错误
  static any(promises) {
    return new LzPromise((resolve, reject) => {
      let reasons = [];
      promises.forEach((promise) => {
        promise.then(
          (res) => {
            resolve(res);
          },
          (err) => {
            reasons.push(err);
            if (reasons.length === promises.length) {
              reject(new AggregateError(reasons));
            }
          }
        );
      });
    });
  }
}

更多好文移步龙仔的个人博客(longzai1024.top/home ),谢谢关注!