实现Promise-采用 Promise A+规范


Promise 介绍

一个 Promise 对象代表一个在这个 promise 被创建出来时不一定已知值的代理。它让你能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。

Promise A+规范: https://promisesaplus.com/

const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";

class PMPromise {
  constructor(executor) {
    this.status = PROMISE_STATUS_PENDING;
    this.value = undefined;
    this.reason = undefined;

    this.onFulfilledFns = [];
    this.onRejectedFns = [];

    const resolve = (value) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          if (this.status !== PROMISE_STATUS_PENDING) return;
          this.status = PROMISE_STATUS_FULFILLED;
          this.value = value;
          this.onFulfilledFns.forEach((fn) => {
            fn(this.value);
          });
        });
      }
    };
    const reject = (reason) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          if (this.status !== PROMISE_STATUS_PENDING) return;
          this.status = PROMISE_STATUS_REJECTED;
          this.reason = reason;
          this.onRejectedFns.forEach((fn) => {
            fn(this.reason);
          });
        });
      }
    };
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  #execuFnWithCatchError(execuFn, value, resolve, reject) {
    try {
      const result = execuFn(value);
      resolve(result);
    } catch (error) {
      reject(error);
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled = onFulfilled || ((value) => value);
    onRejected =
      onRejected ||
      ((err) => {
        throw err;
      });

    return new PMPromise((resolve, reject) => {
      if (this.status === PROMISE_STATUS_FULFILLED) {
        this.onFulfilledFns.push(() => {
          this.#execuFnWithCatchError(onFulfilled, this.value, resolve, reject);
        });
      }
      if (this.status === PROMISE_STATUS_REJECTED) {
        this.onRejectedFns.push(() => {
          this.#execuFnWithCatchError(onRejected, this.reason, resolve, reject);
        });
      }
      if (this.status === PROMISE_STATUS_PENDING) {
        this.onFulfilledFns.push(() => {
          this.#execuFnWithCatchError(onFulfilled, this.value, resolve, reject);
        });
        this.onRejectedFns.push(() => {
          this.#execuFnWithCatchError(onRejected, this.reason, resolve, reject);
        });
      }
    });
  }

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

  finally(onFinally) {
    return this.then(
      () => {
        onFinally();
      },
      () => {
        onFinally();
      }
    );
  }

  static resolve(value) {
    return new PMPromise((resolve) => resolve(value));
  }

  static reject(reason) {
    return new PMPromise((undefined, reject) => reject(reason));
  }

  static all(promiseArr) {
    return new PMPromise((resolve, reject) => {
      const result = [];
      promiseArr.forEach((promise) => {
        promise.then(
          (res) => {
            result.push(res);
            if (promiseArr.length === result.length) {
              resolve(result);
            }
          },
          (err) => {
            reject(err);
          }
        );
      });
    });
  }
  static allSettled(promiseArr) {
    return new PMPromise((resolve, reject) => {
      const result = [];
      promiseArr.forEach((promise) => {
        promise.then(
          (res) => {
            result.push({ status: PROMISE_STATUS_FULFILLED, value: res });
            if (promiseArr.length === result.length) {
              resolve(result);
            }
          },
          (err) => {
            result.push({ status: PROMISE_STATUS_REJECTED, value: err });
            if (promiseArr.length === result.length) {
              resolve(result);
            }
          }
        );
      });
    });
  }

  static race(promiseArr) {
    return new PMPromise((resolve, reject) => {
      promiseArr.forEach((promise) => {
        promise.then(resolve, reject);
      });
    });
  }

  static any(promiseArr) {
    return new PMPromise((resolve, reject) => {
      const result = [];
      promiseArr.forEach((promise) => {
        promise.then(resolve, (err) => {
          result.push(err);
          if (promiseArr.length === result.length) {
            reject(new AggregateError(result));
          }
        });
      });
    });
  }
}

// 以下是测试代码
const promise = new PMPromise((resolve, reject) => {
  // resolve(111)
  reject("error");
});
// promise
//   .then(
//     (res) => {
//       console.log(res)
//     },
//     (err) => {
//       console.log(err)
//     }
//   )
//   .catch((err) => {
//     console.log(err)
//   })
//   .finally(() => {
//     console.log('finally')
//   })

// PMPromise.resolve('resolve').then((res) => {
//   console.log(res)
// })

// PMPromise.reject('reject').catch((err) => {
//   console.log(err)
// })

const p1 = new PMPromise((resolve, reject) => {
  setTimeout(() => {
    // resolve('p1')
    reject("err-p1");
  }, 1000);
});
const p2 = new PMPromise((resolve, reject) => {
  setTimeout(() => {
    // resolve('p2')
    reject("err-p2");
  }, 2000);
});
const p3 = new PMPromise((resolve, reject) => {
  setTimeout(() => {
    // resolve('p3')
    reject("err-p3");
  }, 3000);
});

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

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

// PMPromise.race([p1, p2, p3])
//   .then((res) => {
//     console.log('race', res)
//   })
//   .catch((err) => {
//     console.log('race', err)
//   })

PMPromise.any([p1, p2, p3])
  .then((res) => {
    console.log("any", res);
  })
  .catch((err) => {
    console.log("any", err);
  });

文章作者: PaoMo
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 PaoMo !
  目录