全网最全手写Promise

71 阅读2分钟

也许你在开发中能很熟练使用Promise处理异步任务,但是你真的能手写Promise吗? 熟悉Promise原理已然成为前端人必备基本技能,能把原理付诸代码编写就更棒啦🎉

话不多说,直接上代码吧😎

enum PromiseState {
  pending = "pending",
  fulfilled = "fulfilled",
  rejected = "rejected",
}

/**
 * Promise A+规范
 * @param target
 * @returns
 */
const isPromise = (target) => {
  return target && typeof target.then === "function";
};

const isIterableList = (promises) => {
  return (
    typeof promises[Symbol.iterator] === "function" &&
    typeof promises !== "string"
  );
};

class IPromise<T> {
  state: PromiseState;
  value: T;
  reason: any;
  resolveCallbacks: Array<() => any>;
  rejectedCallbacks: Array<() => void>;
  constructor(executor) {
    const resolve = (value: T) => {
      if (this.state === PromiseState.pending) return;
      this.state = PromiseState.fulfilled;
      this.value = value;
      this.resolveCallbacks.forEach((fn) => fn());
    };
    const reject = (error: any) => {
      if (this.state === PromiseState.pending) return;
      this.state = PromiseState.rejected;
      this.reason = error;
      this.rejectedCallbacks.forEach((fn) => fn());
    };
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
  then(onResove, onReject?) {
    const nextPromise = new IPromise((resolve, reject) => {
      onResove = typeof onResove === "function" ? onResove : (value) => value;
      onReject =
        typeof onReject === "function"
          ? onReject
          : (error) => {
              throw error;
            };
      if (this.state === PromiseState.fulfilled) {
        this.resolveCallbacks.push(() => {
          const result = onResove(this.value);
          this.resolvePromise(result, nextPromise, resolve, reject);
        });
      }
      if (this.state === PromiseState.rejected) {
        this.rejectedCallbacks.push(() => {
          const result = onReject(this.reason);
          this.resolvePromise(result, nextPromise, resolve, reject);
        });
      }
    });
    return nextPromise;
  }
  catch(onReject) {
    onReject =
      typeof onReject === "function"
        ? onReject
        : (error) => {
            throw error;
          };
    return this.then(null, onReject);
  }
  finally(fn: Function) {
    return this.then(
      (value) => {
        return IPromise.resolve(fn()).then(() => value);
      },
      (reason) => {
        return IPromise.resolve(fn()).then(() => {
          throw reason;
        });
      }
    );
  }
  /**
   * 处理then回调函数执行结果
   * @param result
   * @param nextPromise
   * @param resolve
   * @param reject
   */
  private resolvePromise(result, nextPromise, resolve, reject) {
    if (result === nextPromise) {
      return reject(
        new TypeError("Chaining cycle detected for promise #<Promise>")
      );
    }
    if (isPromise(result)) {
      try {
        result.then.call(
          result,
          (ret) => {
            this.resolvePromise(ret, nextPromise, resolve, reject);
          },
          (err) => {
            reject(err);
          }
        );
      } catch (error) {
        reject(error);
      }
    } else {
      resolve(result);
    }
  }
  static resolve(p) {
    return new IPromise((resolve, reject) => {
      if (p instanceof IPromise) {
        return p.then(resolve, reject);
      }
      resolve(p);
    });
  }
  static reject(p) {
    return new IPromise((resolve, reject) => {
      reject(p);
    });
  }
  static all(promises) {
    /**
     * 所有promise fulfilled时才会变成fulfilled状态返回数组值,否则变成rejected
     */
    return new IPromise((resolve, reject) => {
      if (isIterableList(promises)) {
        const list: any = [],
          ret: any = [];
        for (const p of promises) {
          list.push(p);
        }
        if (list.length === 0) resolve(list);
        list.forEach((p, index) => {
          IPromise.resolve(p)
            .then((res) => {
              ret[index] = res;
              if (ret.length === list.length) resolve(ret);
            })
            .catch((err) => {
              reject(err);
            });
        });
      } else {
        reject("Argument is not iterable");
      }
    });
  }
  static race(promises) {
    /**
     * race 状态与第一个改变状态保持一致
     */
    return new IPromise((resolve, reject) => {
      if (isIterableList(promises)) {
        promises.forEach((p) => {
          IPromise.resolve(p)
            .then((res) => {
              resolve(res);
            })
            .catch((error) => {
              reject(error);
            });
        });
      } else {
        reject("Argument is not iterable");
      }
    });
  }
  static any(promises) {
    /**
     * 任一promise fulfilled时保持fulfilled,且then回调获取第一个fulfilled promise返回值
     */
    return new IPromise((resolve, reject) => {
      if (isIterableList(promises)) {
        const errors: any = [];
        promises.forEach((p, index) => {
          IPromise.resolve(p)
            .then((res) => {
              resolve(res);
            })
            .catch((error) => {
              errors[index] = error;
              if (errors.length === promises.length) {
                reject(new AggregateError(errors));
              }
            });
        });
      } else {
        reject("Argument is not iterable");
      }
    });
  }
  static allSettled(promises) {
    /**
     * 不管fulfilled或是rejected,只有所有promise状态改变时,状态才会变成fulfilled,且始终是fulfilled
     */
    return new IPromise((resolve, reject) => {
      if (isIterableList(promises)) {
        const ret: any = [];
        promises.forEach((p, index) => {
          IPromise.resolve(p)
            .then((res) => {
              ret[index] = res;
            })
            .catch((error) => {
              ret[index] = error;
            })
            .finally(() => {
              if (ret.length === promises.length) resolve(ret);
            });
        });
      } else {
        reject("Argument is not iterable");
      }
    });
  }
  static try(task) {
    /**
     * 同步函数同步执行,异步函数异步执行
     */
    return new IPromise((resolve, reject) => {
      try {
        const ret = typeof task === "function" ? task() : task;
        if(isPromise(ret)){
            ret.then.call(ret, resolve, reject)
        }else {
            resolve(ret);
        }
      } catch (error) {
        reject(error);
      }
    });
  }
}

凑合看吧,全靠缘分😂