Promise 链式编程-处理一般、异常、重复引用、reject、pending (七)

92 阅读1分钟

Promise 链式编程-处理一般、异常、重复引用、reject、pending

  <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);
      }
    }

    // 3. 判断各种情况
    // 处理重复引用
    // 处理promise的情况
    // 直接返回resolve(x)
    function resolvePromise(p2, x, resolve, reject) {
      if (x === p2) {
        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 = [];

      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));
          }
        };
        // 1. 处理异常
        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;
              };
        // 2. 返回一个新的 promise
        const p2 = new FXPromise((resolve, reject) => {
          if (this.state === FULFILLED) {
            runAsyncTask(() => {
              // 2.1 处理异常
              try {
                const x = onFulfilled(this.result);
                resolvePromise(p2, x, resolve, reject);
              } catch (error) {
                reject(error);
              }
            });
          } else if (this.state === REJECTED) {
            runAsyncTask(() => {
              // 2.1 处理异常
              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(() => {
                  // 2.1 处理异常
                  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;
      }
    }

    const p = new FXPromise((resolve, reject) => {
      resolve(1);
    });
    const p2 = p.then((res) => {
      return p2;
    });

    p2.then(
      (res) => {},
      (err) => {
        console.log("err:", err);
      }
    );

    // ------------- 测试代码 原生Promise  -------------
    // const p = new Promise((resolve, reject) => {
    //   resolve(1);
    // });
    // const p2 = p.then((res) => {
    //   return p2;
    // });

    // p2.then(
    //   (res) => {},
    //   (err) => {
    //     console.log("err:", err);
    //   }
    // );
  </script>