实现一个简版Promise

手写实现一个符合Promise/A+规范的简版Promise,理解异步编程的原理

问题

Promise是JavaScript中处理异步操作的重要机制。这道题要求实现一个简版的Promise,需要支持:

  • 三种状态:pending、fulfilled、rejected
  • then方法的链式调用
  • 异步状态改变
  • 值的传递和错误捕获

通过手写Promise,可以理解异步编程的原理和Promise的内部实现机制。

解答

// 定义三种状态常量
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    // 初始状态为pending
    this.status = PENDING;
    // 成功的值
    this.value = undefined;
    // 失败的原因
    this.reason = undefined;
    // 成功回调函数队列
    this.onFulfilledCallbacks = [];
    // 失败回调函数队列
    this.onRejectedCallbacks = [];

    // resolve函数
    const resolve = (value) => {
      // 只有pending状态才能转换
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.value = value;
        // 执行所有成功回调
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };

    // reject函数
    const reject = (reason) => {
      // 只有pending状态才能转换
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        // 执行所有失败回调
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };

    // 执行executor,捕获异常
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  // then方法
  then(onFulfilled, onRejected) {
    // 参数校验,确保是函数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    // 返回新的Promise实现链式调用
    const promise2 = new MyPromise((resolve, reject) => {
      // 如果状态已经是fulfilled
      if (this.status === FULFILLED) {
        // 使用setTimeout模拟微任务
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      // 如果状态已经是rejected
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      // 如果状态还是pending,将回调存入队列
      if (this.status === PENDING) {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });

    return promise2;
  }

  // catch方法
  catch(onRejected) {
    return this.then(null, onRejected);
  }

  // 静态resolve方法
  static resolve(value) {
    return new MyPromise((resolve) => {
      resolve(value);
    });
  }

  // 静态reject方法
  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    });
  }
}

// Promise解析函数
function resolvePromise(promise2, x, resolve, reject) {
  // 防止循环引用
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected'));
  }

  // 如果x是Promise实例
  if (x instanceof MyPromise) {
    x.then(resolve, reject);
  } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    // 如果x是对象或函数
    let called = false;
    try {
      const then = x.then;
      if (typeof then === 'function') {
        // 如果then是函数,认为x是thenable对象
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (error) {
      if (called) return;
      called = true;
      reject(error);
    }
  } else {
    // 普通值直接resolve
    resolve(x);
  }
}

使用示例

// 示例1:基本使用
const promise1 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功');
  }, 1000);
});

promise1.then(
  value => {
    console.log(value); // 1秒后输出:成功
    return '第二次处理';
  }
).then(
  value => {
    console.log(value); // 输出:第二次处理
  }
);

// 示例2:错误处理
const promise2 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    reject('失败原因');
  }, 1000);
});

promise2
  .then(value => {
    console.log(value);
  })
  .catch(error => {
    console.log('捕获错误:', error); // 输出:捕获错误: 失败原因
  });

// 示例3:链式调用
new MyPromise((resolve) => {
  resolve(1);
})
  .then(value => {
    console.log(value); // 输出:1
    return value + 1;
  })
  .then(value => {
    console.log(value); // 输出:2
    return value + 1;
  })
  .then(value => {
    console.log(value); // 输出:3
  });

// 示例4:返回Promise
new MyPromise((resolve) => {
  resolve(1);
})
  .then(value => {
    return new MyPromise((resolve) => {
      setTimeout(() => {
        resolve(value * 2);
      }, 1000);
    });
  })
  .then(value => {
    console.log(value); // 1秒后输出:2
  });

// 示例5:静态方法
MyPromise.resolve('直接成功').then(value => {
  console.log(value); // 输出:直接成功
});

MyPromise.reject('直接失败').catch(error => {
  console.log(error); // 输出:直接失败
});

关键点

  • 状态管理:Promise有三种状态(pending、fulfilled、rejected),状态只能从pending转换为fulfilled或rejected,且不可逆
  • 回调队列:使用数组存储then方法注册的回调函数,支持同一个Promise多次调用then
  • 异步执行:使用setTimeout模拟微任务,确保then回调异步执行
  • 链式调用:then方法返回新的Promise实例,实现链式调用
  • 值穿透:当then方法参数不是函数时,实现值的向下传递
  • Promise解析:resolvePromise函数处理then回调返回值,支持返回普通值、Promise实例或thenable对象
  • 循环引用检测:防止then回调返回自身Promise导致的死循环
  • 错误处理:捕获executor和回调函数执行过程中的异常,通过reject传递
  • 参数校验:确保onFulfilled和onRejected是函数类型,提供默认实现
  • 静态方法:实现Promise.resolve和Promise.reject快捷方法