Skip to content

手写Promise实现,遵循Promise/A+规范

TIP

这是手动实现Promise的过程,遵循Promise/A+规范,并附带注释。 Promises/A+规范与ECMAScript中promise有些许不同,在事件执行顺序上有一些差异,所以手动实现的promise与nodejs和V8引擎中执行promise结果会有差异。具体差异可查看文章 V8 promise源码解读https://juejin.cn/post/7055202073511460895

javascript
// 状态常量,promise的三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise {
  #state = PENDING;//状态
  #value = undefined;//传递给resolve的值
  #reason = undefined;//传递给reject的原因
  #onFulfilledCallbacks = [];//then的onFulfilled回调函数,因为then可以连续调用,onFulfilled可能有多个
  #onRejectedCallbacks = [];//then的onRejected回调函数,因为catch可以连续调用,onRejected可能有多个

  //promise的构造函数,executor是一个函数,接收两个参数resolve和reject,分别用于传递成功和失败的值
  //executor函数在promise实例化时立即执行,用于初始化promise的状态和执行异步操作
  constructor(executor) {
    // 如果executor不是函数,则抛出类型错误
    if (typeof executor !== "function") {
      throw new TypeError(
        `Promise resolver ${executor ? Object.prototype.toString.call(executor) : executor} is not a function`,
      );
    }

    /**
     * 定义resolve和reject函数,用于传递成功和失败的值
     * 并将状态设置为fulfilled或rejected,并执行对应的回调函数
    */
    const resolve = (value) => {
      // 如果状态已经是fulfilled或rejected,则忽略;因为promise状态一旦变化,则不能再次改变
      if (this.#state === PENDING) {
        // queueMicrotask是将函数放到下一个微任务中执行
        queueMicrotask(() => {
          if (this.#state !== PENDING) return;// 不要把this.#state !== PENDING和上方this.#state === PENDING弄混淆了,这里并不冲突,因为微任务是异步执行的
          this.#state = FULFILLED;
          this.#value = value;
          this.#onFulfilledCallbacks.forEach((cb) => cb());
        });
      }
    };

    const reject = (reason) => {
      if (this.#state === PENDING) {
        queueMicrotask(() => {
          if (this.#state !== PENDING) return;
          this.#state = REJECTED;
          this.#reason = reason;
          this.#onRejectedCallbacks.forEach((cb) => cb());
        });
      }
    };

    // 执行executor函数,需要把执行错误抛出,不要忘记try catch
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  // then方法,用于添加成功和失败的回调函数,返回一个新的promise实例
  // 成功的回调函数接收成功的值,失败的回调函数接收失败的原因
  // 成功的回调函数和失败的回调函数返回的值,会作为参数,传递给下一个then的回调函数
  // 如果返回值是一个promise实例,则会等待这个promise实例状态改变,然后将结果传递给下一个then的回调函数
  then(onFulfilled, onRejected) {
    // onFulfilled和onRejected可以不传,但是then和catch可以链式调用,需要将promise值或者错误透传
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => value;
    onRejected = typeof onRejected === "function" ? onRejected : (err) => { throw err; };

    // then方法需要返回一个新的promise实例,用于链式调用
    return new MyPromise((resolve, reject) => {
      const fulfilledHandler = () => {
        try {
          // 如果onFulfilled返回的是一个promise实例,则等待这个promise实例状态改变,然后将结果传递给下一个then的回调函数
          const result = onFulfilled(this.#value);
          if (result instanceof MyPromise) {
            result.then(resolve, reject);
          } else {
            resolve(result);
          }
        } catch (e) {
          reject(e);
        }
      };

      const rejectedHandler = () => {
        try {
          // 如果onRejected返回的是一个promise实例,则等待这个promise实例状态改变,然后将结果传递给下一个then的回调函数
          const result = onRejected(this.#reason);
          if (result instanceof MyPromise) {
            result.then(resolve, reject);
          } else {
            resolve(result);
          }
        } catch (e) {
          reject(e);
        }
      };

      if (this.#state === FULFILLED) {
        // 如果状态是fulfilled,则立即执行成功的回调函数
        queueMicrotask(fulfilledHandler);
      } else if (this.#state === REJECTED) {
        // 如果状态是rejected,则立即执行失败的回调函数
        queueMicrotask(rejectedHandler);
      } else if (this.#state === PENDING) {
        // promise的状态是pending,则将成功和失败的回调函数添加到数组中,等待状态改变时执行
        this.#onFulfilledCallbacks.push(fulfilledHandler);
        this.#onRejectedCallbacks.push(rejectedHandler);
      }
    });
  }

  // catch方法,用于添加失败的回调函数,返回一个新的promise实例
  // 失败的回调函数接收失败的原因,返回值会作为参数,传递给下一个then的回调函数
  catch(onRejected) {
    return this.then(undefined, onRejected);
  }

  // finally方法,用于添加一个回调函数,无论promise状态如何,都会执行这个回调函数
  // 返回值会作为参数,传递给下一个then的回调函数
  finally(onFinally) {
    return this.then(
      (value) => {
        onFinally();
        return value;
      },
      (reason) => {
        onFinally();
        throw reason;
      },
    );
  }

  // static方法,用于创建promise实例
  static resolve(value) {
    return new MyPromise((resolve) => resolve(value));
  }

  // static方法,用于创建失败的promise实例
  static reject(err) {
    return new MyPromise((_, reject) => reject(err));
  }

  // static all方法接收一个promise数组,返回一个新的promise实例,所有promise全部成功才成功,有一个失败则失败
  static all(promiseArray) {
    return new MyPromise((resolve, reject) => {
      const result = [];
      let count = 0;
      const len = promiseArray.length;

      if (len === 0) {
        resolve(result);
        return;
      }

      promiseArray.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          (value) => {
            result[index] = value;
            count++;
            if (count === len) {
              resolve(result);
            }
          },
          (err) => {
            reject(err);
          },
        );
      });
    });
  }

  // static allSettled方法接收一个promise数组,返回一个新的promise实例,无论promise状态如何,都会返回一个对象数组,包含状态和值
  static allSettled(promiseArray) {
    return new MyPromise((resolve) => {
      const result = [];
      let count = 0;
      const len = promiseArray.length;

      if (len === 0) {
        resolve(result);
        return;
      }

      promiseArray.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          (value) => {
            result[index] = { status: FULFILLED, value };
            count++;
            if (count === len) {
              resolve(result);
            }
          },
          (reason) => {
            result[index] = { status: REJECTED, reason };
            count++;
            if (count === len) {
              resolve(result);
            }
          },
        );
      });
    });
  }

  // static any方法接收一个promise数组,返回一个新的promise实例,只要有一个promise成功,则成功,全部失败则失败
  // 失败的原因是一个AggregateError实例,包含所有失败的原因
  static any(promiseArray) {
    return new MyPromise((resolve, reject) => {
      const reason = [];
      let count = 0;
      const len = promiseArray.length;

      if (len === 0) {
        reject(new AggregateError(reason));
        return;
      }

      promiseArray.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          (value) => {
            resolve(value);
          },
          (err) => {
            reason[index] = err;
            count++;
            if (count === len) {
              reject(new AggregateError(reason));
            }
          },
        );
      });
    });
  }

  // static race方法接收一个promise数组,返回一个新的promise实例,只要有一个promise成功,则成功,全部失败则失败
  static race(promiseArray) {
    return new MyPromise((resolve, reject) => {
      promiseArray.forEach((promise) => {
        MyPromise.resolve(promise).then(resolve, reject);
      });
    });
  }
}
最近更新