Promise 静态方法resolve、reject、race、all、allSettled、any 实现

73 阅读3分钟

静态方法resolve、reject、race、all、allSettled、any 实现

  <script>
    function runAsyncTask(callback) {
      if (typeof queueMicrotask === "function") {
        queueMicrotask(callback);
      } else if (typeof MutationObserver === "function") {
        const obs = new MutationObserver(callback);
        const divNode = document.createElement("div");
        obs.observe(divNode, { childList: true });
        divNode.innerText = "fx666";
      } else {
        setTimeout(callback, 0);
      }
    }

    function resolvePromise(p2, x, resolve, reject) {
      if (x === p2) {
        // console.log('返回了p2')
        // 2. 抛出错误 Chaining cycle detected for promise #<Promise>
        throw new TypeError("Chaining cycle detected for promise #<Promise>");
      }
      if (x instanceof FXPromise) {
        x.then(
          (res) => resolve(res),
          (err) => reject(err)
        );
      } else {
        resolve(x);
      }
    }

    const PENDING = "pending";
    const FULFILLED = "fulfilled";
    const REJECTED = "rejected";

    class FXPromise {
      state = PENDING;
      result = undefined;
      #handlers = []; // [{onFulfilled,onRejected},... n个]  p.then  p.then  ... 一个实例可以同时then,每个都要有对应的回调

      constructor(fn) {
        const resolveFunc = (res) => {
          if (this.state === PENDING) {
            this.result = res;
            this.state = FULFILLED;
            this.#handlers.forEach(({ onFulfilled }) => {
              onFulfilled(this.result);
            });
          }
        };
        const rejectFunc = (res) => {
          if (this.state === PENDING) {
            this.result = res;
            this.state = REJECTED;
            this.#handlers.forEach(({ onRejected }) => onRejected(this.result));
          }
        };
        try {
          fn(resolveFunc, rejectFunc);
        } catch (error) {
          rejectFunc(error);
        }
      }

      then(onFulfilled, onRejected) {
        onFulfilled =
          typeof onFulfilled === "function" ? onFulfilled : (x) => x;
        onRejected =
          typeof onRejected === "function"
            ? onRejected
            : (x) => {
                throw x;
              };
        const p2 = new FXPromise((resolve, reject) => {
          if (this.state === FULFILLED) {
            runAsyncTask(() => {
              try {
                const x = onFulfilled(this.result);
                resolvePromise(p2, x, resolve, reject);
              } catch (error) {
                reject(error);
              }
            });
          } else if (this.state === REJECTED) {
            runAsyncTask(() => {
              try {
                const x = onRejected(this.result);
                resolvePromise(p2, x, resolve, reject);
              } catch (error) {
                reject(error);
              }
            });
          } else if (this.state === PENDING) {
            this.#handlers.push({
              onFulfilled: (res) => {
                runAsyncTask(() => {
                  try {
                    const x = onFulfilled(res);
                    resolvePromise(p2, x, resolve, reject);
                  } catch (error) {
                    reject(error);
                  }
                });
              },
              onRejected: (res) => {
                runAsyncTask(() => {
                  try {
                    const x = onRejected(res);
                    resolvePromise(p2, x, resolve, reject);
                  } catch (error) {
                    reject(error);
                  }
                });
              },
            });
          }
        });
        return p2;
      }

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

      finally(onFinally) {
        return this.then(onFinally, onFinally);
      }
      
      /**
       * 静态方法-resolve
       *  1. 判断传入值
       *  2.1 Promise直接返回
       *  2.2 转为Promise并返回(fulfilled状态)
       * */
      static resolve(value) {
        if (value instanceof FXPromise) {
          return value;
        }
        return new FXPromise((resolve) => {
          resolve(value);
        });
      }

     /**
       * 静态方法-reject
       * 1. 返回rejected状态的Promise
       * */
      static reject(value) {
        return new FXPromise((undefined, reject) => {
          reject(value);
        });
      }
      /**
       * 静态方法-race
       * 1. 返回Promise
       * 2. 判断是否为数组 错误信息:Argument is not iterable
       * 3. 等待第一个敲定
       * */
      static race(promises) {
        return new FXPromise((resolve, reject) => {
          if (!Array.isArray(promises)) {
            reject(new TypeError("Argument is not iterable"));
          }
          promises.forEach((p) => {
            FXPromise.resolve(p).then(
              (res) => {
                resolve(res);
              },
              (err) => {
                reject(err);
              }
            );
          });
        });
      }

      /**
       * 静态方法-all
       *  1. 返回Promise实例
       *  2. 判断是否为数组 错误信息:Argument is not iterable
       *  3. 空数组直接兑现
       *  4. 处理全部兑现
       *    4.1 记录结果:索引来记录,保证结果的顺序和Promise数组的顺序一致
       *    4.2 判断全部兑现:通过兑现的次数进行判断,保证可以获取到所有的结果
       *  5. 处理第一个拒绝
       * */
      static all(promises) {
        // 1. 返回Promise实例
        return new FXPromise((resolve, reject) => {
          // 2. 判断是否为数组
          if (!Array.isArray(promises)) {
            reject(new TypeError("Argument is not iterable"));
          }
          // 3. 空数组直接兑现
          promises.length === 0 && resolve(promises);
          // 4.1 记录结果
          const results = [];
          let count = 0;
          promises.forEach((p, index) => {
            FXPromise.resolve(p).then(
              (res) => {
                results[index] = res;
                // 4.2 判断全部兑现
                count++;
                count === promises.length && resolve(results);
              },
              (err) => {
                // 5. 处理第一个拒绝
                reject(err);
              }
            );
          });
        });
      }

      /**
       * 静态方法-allSettled
       * 1. 返回Promise
       * 2. 数组判断 错误信息: Argument is not iterable
       * 3. 为空直接敲定
       * 4. 等待全部敲定
       *  4.1 记录结果
       *  4.2 处理兑现{status:'fulfilled',value:''}
       *  4.3 处理拒绝{status:'rejected',reason:''}
       * */
      static allSettled() {
        // 1. 返回Promise实例
        return new FXPromise((resolve, reject) => {
          // 2. 判断是否为数组
          if (!Array.isArray(promises)) {
            reject(new TypeError("Argument is not iterable"));
          }
          // 3. 空数组直接兑现
          promises.length === 0 && resolve(promises);
          // 4. 等待全部敲定
          // 4.1 记录结果
          const results = [];
          let count = 0;
          promises.forEach((p, index) => {
            FXPromise.resolve(p).then(
              (res) => {
                // 4.2 处理兑现{status:'fulfilled',value:''}
                results[index] = { status: FULFILLED, value: res };
                count++;
                count === promises.length && resolve(results);
              },
              (err) => {
                // 4.3 处理拒绝{status:'rejected',reason:''}
                results[index] = { status: REJECTED, value: res };
                count++;
                count === promises.length && resolve(results);
              }
            );
          });
        });
      }

      /**
       * 静态方法-any
       * 1. 返回Promise,数组判断 错误信息: Argument is not iterable
       * 2. 空数组直接拒绝 AggregateError([错误原因1..],All promises were rejected)
       * 3. 等待结果
       *  3.1 第一个兑现
       *  3.2 全部拒绝
       */
      static any(promises) {
        // 1. 返回Promise实例
        return new FXPromise((resolve, reject) => {
          // 2. 判断是否为数组
          if (!Array.isArray(promises)) {
            reject(new TypeError("Argument is not iterable"));
          }
          // 3. 空数组直接兑现
          promises.length === 0 &&
            reject(new AggregateError(promises, "All promises were rejected"));
          // 4.1 记录结果
          const errors = [];
          let count = 0;
          promises.forEach((p, index) => {
            FXPromise.resolve(p).then(
              (res) => {
                resolve(res);
              },
              (err) => {
                // 5. 处理第一个拒绝
                errors[index] = err;
                count++;
                count === promises.length &&
                  reject(
                    new AggregateError(errors, "All promises were rejected")
                  );
              }
            );
          });
        });
      }
    }
  </script>