前端手写: Promise

5 阅读1分钟
// 手写简易版 Promise
class MyPromise {
  // 定义三种状态
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';
  static REJECTED = 'rejected';

  constructor(executor) {
    // 初始状态
    this.status = MyPromise.PENDING;
    // 成功值 / 失败原因
    this.value = undefined;
    this.reason = undefined;
    // 存放 then 回调(解决异步)
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    // 成功函数
    const resolve = (value) => {
      if (this.status !== MyPromise.PENDING) return;
      this.status = MyPromise.FULFILLED;
      this.value = value;
      // 执行所有成功回调
      this.onFulfilledCallbacks.forEach(fn => fn());
    };

    // 失败函数
    const reject = (reason) => {
      if (this.status !== MyPromise.PENDING) return;
      this.status = MyPromise.REJECTED;
      this.reason = reason;
      // 执行所有失败回调
      this.onRejectedCallbacks.forEach(fn => fn());
    };

    // 执行器函数,立即执行
    try {
      executor(resolve, reject);
    } catch (error) {
      // 捕获执行器异常,直接 reject
      reject(error);
    }
  }

  // then 方法
  then(onFulfilled, onRejected) {
    // 参数默认值(规范要求)
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    // 返回新 Promise 支持链式调用
    return new MyPromise((resolve, reject) => {
      // 同步:状态已确定
      if (this.status === MyPromise.FULFILLED) {
        setTimeout(() => {
          try {
            const result = onFulfilled(this.value);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        });
      }

      if (this.status === MyPromise.REJECTED) {
        setTimeout(() => {
          try {
            const result = onRejected(this.reason);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        });
      }

      // 异步:状态还在 pending,先存起来
      if (this.status === MyPromise.PENDING) {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const result = onFulfilled(this.value);
              resolve(result);
            } catch (error) {
              reject(error);
            }
          });
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const result = onRejected(this.reason);
              resolve(result);
            } catch (error) {
              reject(error);
            }
          });
        });
      }
    });
  }

  // 简易 catch 方法
  catch(onRejected) {
    return this.then(undefined, onRejected);
  }
}