实现Promise相关方法

手写实现Promise方法,包括Promise构造函数、then、catch、finally以及静态方法resolve、reject、all、race、allSettled等

问题

Promise是JavaScript中处理异步操作的重要机制。本题要求手写实现Promise的功能,包括:

  1. Promise构造函数及基本状态管理
  2. 实例方法:then、catch、finally
  3. 静态方法:resolve、reject、all、race、allSettled、any

通过实现这些方法,理解Promise的工作原理和异步编程模式。

解答

// Promise的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

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

    // 成功时调用
    const resolve = (value) => {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.value = value;
        // 执行所有成功回调
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };

    // 失败时调用
    const reject = (reason) => {
      if (this.state === PENDING) {
        this.state = 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) => {
      if (this.state === FULFILLED) {
        // 使用微任务
        queueMicrotask(() => {
          try {
            const x = onFulfilled(this.value);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      } else if (this.state === REJECTED) {
        queueMicrotask(() => {
          try {
            const x = onRejected(this.reason);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      } else if (this.state === PENDING) {
        // 异步情况,将回调存入队列
        this.onFulfilledCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              const x = onFulfilled(this.value);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
        });
        this.onRejectedCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              const x = onRejected(this.reason);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
        });
      }
    });

    return promise2;
  }

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

    if (x instanceof MyPromise) {
      // 如果x是Promise,则等待其状态改变
      x.then(resolve, reject);
    } else {
      // 普通值直接resolve
      resolve(x);
    }
  }

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

  // finally方法
  finally(callback) {
    return this.then(
      value => MyPromise.resolve(callback()).then(() => value),
      reason => MyPromise.resolve(callback()).then(() => { throw reason })
    );
  }

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

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

  // Promise.all - 所有成功才成功
  static all(promises) {
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(new TypeError('Argument must be an array'));
      }

      const results = [];
      let completedCount = 0;
      const total = promises.length;

      if (total === 0) {
        return resolve(results);
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            results[index] = value;
            completedCount++;
            if (completedCount === total) {
              resolve(results);
            }
          },
          reason => {
            reject(reason); // 任何一个失败就立即reject
          }
        );
      });
    });
  }

  // Promise.race - 第一个完成的结果
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(new TypeError('Argument must be an array'));
      }

      promises.forEach(promise => {
        MyPromise.resolve(promise).then(resolve, reject);
      });
    });
  }

  // Promise.allSettled - 等待所有Promise完成
  static allSettled(promises) {
    return new MyPromise((resolve) => {
      if (!Array.isArray(promises)) {
        return resolve([]);
      }

      const results = [];
      let completedCount = 0;
      const total = promises.length;

      if (total === 0) {
        return resolve(results);
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            results[index] = { status: 'fulfilled', value };
            completedCount++;
            if (completedCount === total) {
              resolve(results);
            }
          },
          reason => {
            results[index] = { status: 'rejected', reason };
            completedCount++;
            if (completedCount === total) {
              resolve(results);
            }
          }
        );
      });
    });
  }

  // Promise.any - 任何一个成功就成功
  static any(promises) {
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(new TypeError('Argument must be an array'));
      }

      const errors = [];
      let rejectedCount = 0;
      const total = promises.length;

      if (total === 0) {
        return reject(new AggregateError([], 'All promises were rejected'));
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            resolve(value); // 任何一个成功就立即resolve
          },
          reason => {
            errors[index] = reason;
            rejectedCount++;
            if (rejectedCount === total) {
              reject(new AggregateError(errors, 'All promises were rejected'));
            }
          }
        );
      });
    });
  }
}

使用示例

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

promise1.then(value => {
  console.log(value); // 输出: 成功
  return '链式调用';
}).then(value => {
  console.log(value); // 输出: 链式调用
});

// catch使用
const promise2 = new MyPromise((resolve, reject) => {
  reject('失败了');
});

promise2.catch(error => {
  console.log(error); // 输出: 失败了
});

// finally使用
const promise3 = new MyPromise((resolve) => {
  resolve('完成');
});

promise3
  .finally(() => {
    console.log('清理工作'); // 无论成功失败都执行
  })
  .then(value => {
    console.log(value); // 输出: 完成
  });

// Promise.all使用
MyPromise.all([
  MyPromise.resolve(1),
  MyPromise.resolve(2),
  MyPromise.resolve(3)
]).then(results => {
  console.log(results); // 输出: [1, 2, 3]
});

// Promise.race使用
MyPromise.race([
  new MyPromise(resolve => setTimeout(() => resolve('慢'), 1000)),
  new MyPromise(resolve => setTimeout(() => resolve('快'), 500))
]).then(result => {
  console.log(result); // 输出: 快
});

// Promise.allSettled使用
MyPromise.allSettled([
  MyPromise.resolve(1),
  MyPromise.reject('错误'),
  MyPromise.resolve(3)
]).then(results => {
  console.log(results);
  // 输出: [
  //   { status: 'fulfilled', value: 1 },
  //   { status: 'rejected', reason: '错误' },
  //   { status: 'fulfilled', value: 3 }
  // ]
});

// Promise.any使用
MyPromise.any([
  MyPromise.reject('错误1'),
  MyPromise.resolve('成功'),
  MyPromise.reject('错误2')
]).then(result => {
  console.log(result); // 输出: 成功
});

关键点

  • 状态管理:Promise有三种状态(pending、fulfilled、rejected),状态一旦改变就不可逆
  • 回调队列:使用数组存储异步情况下的回调函数,状态改变时统一执行
  • 微任务:使用queueMicrotask确保回调在微任务队列中执行,符合Promise规范
  • 链式调用:then方法返回新的Promise实例,支持链式调用
  • 值穿透:then方法的参数不是函数时,提供默认函数实现值穿透
  • 循环引用检测:在resolvePromise中检测并防止Promise循环引用
  • Promise.all:所有Promise成功才成功,任一失败立即失败,保持结果顺序
  • Promise.race:返回第一个完成的Promise结果,无论成功或失败
  • Promise.allSettled:等待所有Promise完成,返回所有结果的状态和值
  • Promise.any:任一Promise成功即成功,全部失败才失败
  • 错误处理:使用try-catch捕获同步错误,通过reject传递异步错误