手写Promise

117 阅读2分钟

实现了Promise所有实例方法和静态方法(不考虑边界情况),其实主要是then的实现。
1.写完感觉自己对函数编程有了新的认识,刚开始还是有点绕的,各种回调,彻底掌握then函数后就感觉很妙。
2.对Promise也是知其然知其所以然。

// 定义状态
const STATUS_PENDING = 'pending';
const STATUS_FULFILLED = 'fulfilled';
const STATUS_REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    this.status = STATUS_PENDING;
    this.onFulfilledFns = [];
    this.onRejectedFns = [];
    this.value = undefined;
    this.reason = undefined;

    const resolve = value => {
      // 状态控制
      if (this.status === STATUS_PENDING) {
        this.status = STATUS_FULFILLED;
        this.value = value;
        // 开启微任务事件
        queueMicrotask(() => {
          // 执行then方法接收的回调函数,并回传参数
          this.onFulfilledFns.forEach(fn => fn(value));
        });
      }
    };

    const reject = reason => {
      if (this.status === STATUS_PENDING) {
        this.status = STATUS_FULFILLED;
        this.reason = reason;
        queueMicrotask(() => {
          this.onRejectedFns.forEach(fn => fn(reason));
        });
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    // 默认值设置,兼容链式调用
    const defaultFulfilled = () => {
      return this.value;
    };
    const defaultRejected = () => {
      // 通过抛出异常触发失败捕获
      throw this.reason;
    };
    onFulfilled = onFulfilled ?? defaultFulfilled;
    onRejected = onRejected ?? defaultRejected;

    // 默认返回一个新的promise,支持链式调用
    return new MyPromise((resolve, reject) => {
      // 成功的回调收集
      this.onFulfilledFns.push(value => {
        // 将执行结果传递下去,且处理异常
        try {
          const res = onFulfilled(value);
          resolve(res);
        } catch (error) {
          reject(error);
        }
      });

      // 失败的回调收集
      this.onRejectedFns.push(reason => {
        try {
          const res = onRejected(reason);
          resolve(res);
        } catch (error) {
          reject(error);
        }
      });
    });
  }

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

  finally(onFinally) {
    // 调用resolve/reject都会最终执行
    return this.then(onFinally, onFinally);
  }

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

  static reject(reason) {
    return new MyPromise((resolve, reject) => reject(reason));
  }

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const values = [];
      promises.forEach(p => {
        p.then(
          res => {
            values.push(res);
            if (values.length === promises.length) {
              // 所有都成功时才返回resolve
              resolve(values);
            }
          },
          // 有一个失败直接reject
          reject
        );
      });
    });
  }

  // 所有promise都变更状态后返回resolve
  static allSettled(promises) {
    return new MyPromise(resolve => {
      const values = [];
      promises.forEach(p => {
        p.then(res => {
          values.push({ status: STATUS_FULFILLED, value: res });
          if (values.length === promises.length) resolve(values);
        }).catch(err => {
          values.push({ status: STATUS_REJECTED, reason: err });
          if (values.length === promises.length) resolve(values);
        });
      });
    });
  }

  // 当任何一个promise变更状态时,返回对应res/rej
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach(p => p.then(resolve, reject));
    });
  }

  // 等待一个resolve,如果全部都是reject则返回AggregateError错误
  static any(promises) {
    return new MyPromise((resolve, reject) => {
      const reasons = [];
      promises.forEach(p => {
        p.then(resolve).catch(err => {
          reasons.push(err);
          if (reasons.length === promises.length) {
            reject(new AggregateError(reasons));
          }
        });
      });
    });
  }
}

// test 实例方法
// const promise = new MyPromise((resolve, reject) => {
//   setTimeout(() => {
//     resolve({ name: 'xdl' });
//     reject('err');
//   }, 1000);
//   // throw new Error('promise err');
// });

// promise
//   .catch(err => {
//     console.log('err', err);
//     // return '123';
//     throw 'err 111111';
//   })
//   .then(res => {
//     console.log('res', res);
//   })
//   .catch(err => {
//     console.log('err2', err);
//   })
//   .then(res => {
//     console.log('res2', res);
//     throw 'err 333333';
//   })
//   .catch(err => {
//     console.log('err3', err);
//   })
//   .finally(() => {
//     console.log('finally');
//     throw 'err';
//   })
//   .then(
//     res => {
//       console.log('---res', res);
//     },
//     err => {
//       console.log('---err', err);
//     }
//   );

// promise.catch(err => {
//   console.log('p2  err', err);
// });

// promise.then(res => {
//   console.log('p3  res:', res);
// });

// promise.then(res => {
//   console.log('p4  res:', res);
// });

// test 静态方法
// MyPromise.resolve('success').then(res => console.log('res', res));
// MyPromise.reject('failed').catch(err => console.log('err', err));
const p1 = new MyPromise((res, rej) => {
  setTimeout(() => {
    rej('p1');
  }, 3000);
});
const p2 = new MyPromise((res, rej) => {
  setTimeout(() => {
    rej('p2');
  }, 2000);
});
const p3 = new MyPromise((res, rej) => {
  setTimeout(() => {
    res('p3');
  }, 3000);
});

// MyPromise.all([p1, p2, p3])
//   .then(res => {
//     console.log('res', res);
//   })
//   .catch(err => {
//     console.log('err', err);
//   });
// MyPromise.allSettled([p1, p2, p3])
//   .then(res => {
//     console.log('res', res);
//   })
//   .catch(err => {
//     console.log('err', err);
//   });

MyPromise.any([p1, p2, p3])
  .then(res => {
    console.log('res', res);
  })
  .catch(err => {
    console.log('err', err.errors, err.name);
  });