一梦七年。
一派青春撞了南墙,一生热爱回头太难。
文章 20
标签 29
分类 11
手写Promise

手写Promise

Promise 的简单手写实现,没有太严谨,有问题请指正,会及时修改,更多方法的实现后续补充。

Promise 的手写实现

手写实现代码

参照原生的 Promise 输入输出一步步实现。

/*
 * 手写Promise
 */
class MyPromise {
  #state = "pending"; // promise状态
  #resolveCallBacks = []; // 成功的回调队列
  #rejectCallBack = null; // 失败的回调
  #value = null; // promise当前值

  constructor(fn) {
    // 构造函数参数必须是函数
    if (!fn || typeof fn !== "function") {
      throw new Error("Promise resolver undefined is not a function");
    }

    this.#state = "pending";
    this.#resolveCallBacks = [];
    this.#rejectCallBack = null;

    const reject = (error) => {
      setTimeout(() => {
        if (this.#state === "pending") {
          this.#state = "rejected";
          this.#value = error;
          // reject状态时,没有传递异常处理函数报个错误提示
          if (typeof this.#rejectCallBack === "function") {
            this.#rejectCallBack(error);
          } else {
            console.error("Uncaught (in promise) " + error);
          }
        }
      });
    };

    const resolve = (response) => {
      // resolve参数为promise对象时递归处理
      if (response instanceof MyPromise) {
        return response.then(resolve, reject);
      }
      setTimeout(() => {
        if (this.#state === "pending") {
          this.#state = "fulfilled";
          this.#value = response;
          this.#resolveCallBacks.forEach((cb) => cb(response));
        }
      });
    };

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

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

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

  // 静态all方法
  static all(promises) {
    if (!Array.isArray(promises)) {
      return MyPromise.reject(
        new TypeError(
          `${promises} is not iterable (cannot read property Symbol(Symbol.iterator)`
        )
      );
    } else {
      return new MyPromise((resolve, reject) => {
        const len = promises.length;
        const results = [];
        const resolveResults = (value, i) => {
          results[i] = value;
          if (i + 1 === len) {
            resolve(results);
          }
        };
        for (let i = 0; i < len; i++) {
          const cur = promises[i];
          // 有then方法的调用then方法后存值,没有的直接存值
          if (cur && typeof cur.then === "function") {
            cur.then((res) => {
              resolveResults(res, i);
            }, reject);
          } else {
            resolveResults(cur, i);
          }
        }
      });
    }
  }

  then(success, error) {
    return new MyPromise((resolve, reject) => {
      /* 参数不是函数时转换为直接返回最终结果的函数 */
      if (typeof success !== "function") {
        success = (res) => res;
      }

      /* 异常处理参数不是函数时转换为直接抛出异常的函数 */
      if (typeof error !== "function") {
        error = (err) => {
          throw err;
        };
      }

      const nextTick = globalThis.setImmediate || setTimeout;

      if (this.#state === "pending") {
        this.#resolveCallBacks.push((res) => {
          nextTick(() => {
            try {
              resolve(success(res));
            } catch (error) {
              reject(error);
            }
          });
        });
        if (typeof this.#rejectCallBack !== "function") {
          this.#rejectCallBack = (err) => {
            nextTick(() => {
              try {
                resolve(error(err));
              } catch (error) {
                reject(error);
              }
            });
          };
        }
      }

      if (this.#state === "fulfilled") {
        nextTick(() => {
          try {
            resolve(success(this.#value));
          } catch (error) {
            reject(error);
          }
        });
      }

      if (this.#state === "rejected") {
        nextTick(() => {
          try {
            reject(error(this.#value));
          } catch (error) {
            reject(error);
          }
        });
      }
    });
  }

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

  finally(fn) {
    return this.then(
      (res) => MyPromise.resolve(fn()).then(() => res),
      (res) =>
        MyPromise.resolve(fn()).then(() => {
          throw res;
        })
    );
  }
}

测试用例

resolve 为一个 reject 的 promise:

const myPromise = new MyPromise((resolve, reject) => {
  resolve(
    new MyPromise((res, rej) => {
      setTimeout(() => {
        rej("err123");
      }, 1000);
    })
  );
});

myPromise
  .then((res) => {
    console.log(res);
  })
  .catch((err) => {
    console.log(err); // opt: err123
  });

resolve 为一个 resolve 的 promise:

const myPromise = new MyPromise((resolve, reject) => {
  resolve(
    new MyPromise((res, rej) => {
      setTimeout(() => {
        res("res123");
      }, 1000);
    })
  );
});

myPromise
  .then((res) => {
    console.log(res); // opt: res123
  })
  .catch((err) => {
    console.log(err);
  });

resolve 为一个普通值:

const myPromise = new MyPromise((resolve, reject) => {
  resolve("res123");
});

myPromise
  .then((res) => {
    console.log(res); // 1、 opt: res123
    return "res234";
  })
  .then((res) => {
    console.log(res); // 2、opt: res234
    throw new Error("err");
  })
  .catch((err) => {
    console.log(err); // 3、Error: err....
  });

reject:

const myPromise = new MyPromise((resolve, reject) => {
  reject("err123");
});

myPromise
  .then((res) => {
    console.log(res);
  })
  .catch((err) => {
    console.log(err); // opt: err123
  })
  .catch((err) => {
    // 前面的catch生效后,后面的catch就会被忽略,即只能捕获一次
    console.log("err:", err);
  });

finally:

const myPromise = new MyPromise((resolve, reject) => {
  resolve("res123");
});

myPromise
  .then((res) => {
    console.log(res); // 1、 opt: res123
    return "res234";
  })
  .catch((err) => console.log("err1", err))
  .finally((a) => {
    console.log("finally:", a); // 2、opt: finally: undefined
    return "finally";
  })
  .then((res) => {
    console.log(res); // 2、opt: res234
    throw new Error("err");
  })
  .catch((err) => {
    console.log(err); // 3、Error: err....
  });

reject 的 finally:

const myPromise = new MyPromise((resolve, reject) => {
  reject("err123");
});

myPromise
  .catch((err) => {
    console.log("err:", err); // 1、opt: err: err123
  })
  .finally((a) => {
    console.log("finally:", a); // 2、opt: finally: undefined
  });

all 方法:

MyPromise.all([1, 2, 3, MyPromise.resolve(4)]); // opt: [1, 2, 3, 4];
MyPromise.all([1, 2, 3, MyPromise.reject(4)]); // reject:4