Promise手写

88 阅读1分钟

function MyPromise(fn) {
  let value = null;
  let state = "pending";
  let callbacks = [];
  this.then = function (onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      handle({
        onFulfilled: onFulfilled || null,
        onRejected: onRejected || null,
        resolve: resolve,
        reject,
      });
    });
  };
  this.catch = function (onError) {
    return this.then(null, onError);
  };
  this.finally = function (onDone) {
    this.then(onDone, onDone);
  };
  function handle(cb) {
    if (state === "pending") {
      callbacks.push(cb);
      return; // 支持链式调用
    }
    let callback = state === "fulfilled" ? cb.onFulfilled : cb.onRejected;
    let ret;
    if (callback === null) {
      cb = state === "fulfilled" ? callback.resolve : callback.reject;
      cb(value);
      return;
    }
    try {
      ret = callback(value);
      cb.resolve(ret);
    } catch (e) {
      cb.reject(e);
    }
  }
  resolve = function (newValue) {
    if (
      newValue &&
      (typeof newValue === "object" || typeof newValue === "function")
    ) {
      var then = newValue.then;
      if (typeof then === "function") {
        then.call(newValue, resolve);
        return;
      }
    }
    value = newValue;
    state = "fulfilled";
    execute();
  };
  reject = function (reason) {
    state = "rejected";
    value = reason;
    execute();
  };
  execute = function () {
    setTimeout(() => {
      // 保证执行cb时候,已经全部加入callbacks队列了
      callbacks.forEach((cb) => {
        handle(cb);
      });
    }, 0);
  };
  fn(resolve, reject);
}
MyPromise.all = function (promises) {
  return new MyPromise((resolve, reject) => {
    // 参数判断
    if (!Array.isArray(promises)) {
      throw new TypeError("promises must be an array");
    }
    let result = []; // 存放结果
    let count = 0; // 记录有几个resolved
    promises.forEach((promise, index) => {
      promise.then(
        (res) => {
          result[index] = res;
          count++;
          count === promises.length && resolve(result); // 判断是否已经完成
        },
        (err) => {
          reject(err);
        }
      );
    });
  });
};
MyPromise.race = function (promises) {
  return new MyPromise((resolve, reject) => {
    promises.forEach((promise) => {
        promise.then(resolve, reject);
    })
  });
};
MyPromise.allSettled = function (values) {
  let promises = [].slice.call(values);
  return new MyPromise((resolve, reject) => {
    let result = [],
      count = 0;
    promises.forEach((promise) => {
      promise.then((value) => {
          result.push({ status: "fulfilled", value });
        })
        .catch((err) => {
          result.push({ status: "rejected", value: err });
        })
        .finally(() => {
          if (++count === promise.length) {
            resolve(result);
          }
        });
    });
  });
};