【JS】实现Promise

193 阅读3分钟

参考

代码

// 解析中间promise(promise2)
const resolvePromise = (x, promise2, resolve, reject) => {
  // 不能循环引用Promise
  if (x === promise2) {
    const err = new TypeError("不能循环引用promise!");
    return reject(err);
  }
  // 如果x为对象或者函数,则做进一步判断,
  // 否则直接resolve(x)
  if (x != null && (typeof x === "object" || typeof x === "function")) {
    // 定义called,用于标记是否已调用过resolve或reject
    let called = false;
    // 尝试调用
    try {
      // 因为then可能为getter,所以不能直接调x.then,
      const then = x.then;
      // 为了兼容其他Promise实现,不能直接用instanof对x进行判断
      // 只要x是一个thenable的对象即可,否则,直接resolve(x)
      if (typeof then === "function") {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            // 递归解析
            resolvePromise(y, promise2, resolve, reject);
          },
          (reason) => {
            if (called) return;
            called = true;
            reject(reason);
          }
        );
      } else {
        resolve(x);
      }
    } catch (err) {
      // 如果过程中出错,则reject(err)
      if (called) return;
      called = true;
      reject(err);
    }
  } else {
    resolve(x);
  }
};

// 状态枚举
const STATUS = {
  PENDING: Symbol("PENDING"),
  RESOLVED: Symbol("FULFILLED"),
  REJECTED: Symbol("REJECTED"),
};

// MyPromise
class MyPromise {
  // 构造方法
  constructor(executor) {
    // 初始化状态为Pending
    this.status = STATUS.PENDING;
    // 初始化value和reason
    this.value = undefined;
    this.reason = undefined;
    // 初始化回调队列
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    // 实现resolve
    const resolve = (value) => {
      // 如果状态不为pending,则返回
      if (this.status !== STATUS.PENDING) return;
      // 将状态改变为fulfilled
      this.status = STATUS.RESOLVED;
      // 设置value
      this.value = value;
      // 执行resolve后的回调函数
      this.onResolvedCallbacks.forEach((callback) => callback());
    };
    // 实现reject,同resolve
    const reject = (reason) => {
      if (this.status !== STATUS.PENDING) return;
      this.status = STATUS.REJECTED;
      this.reason = reason;
      this.onRejectedCallbacks.forEach((callback) => callback());
    };
    // 执行
    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }

  // MyPromise.prototype.then
  then(onResolved, onRejected) {
    // 实现值穿透
    if (typeof onResolved !== "function")
      onResolved = (value) => {
        return value;
      };
    if (typeof onRejected !== "function")
      onRejected = (reason) => {
        throw reason;
      };
    // 创建新的promise
    const promise2 = new MyPromise((resolve, reject) => {
      // 区分状态
      switch (this.status) {
        // promise位于pending状态时,暂时还无法确定结果,
        // 所以先将resolve和reject的回调函数添加到回调数组中
        case STATUS.PENDING:
          this.onResolvedCallbacks.push(() => {
            // 模拟异步
            setTimeout(() => {
              try {
                // 获取then的返回值
                const x = onResolved(this.value);
                // 对返回值进行解析
                resolvePromise(x, promise2, resolve, reject);
              } catch (err) {
                reject(err);
              }
            }, 0);
          });
          this.onRejectedCallbacks.push(() => {
            setTimeout(() => {
              try {
                const x = onRejected(this.reason);
                resolvePromise(x, promise2, resolve, reject);
              } catch (err) {
                reject(err);
              }
            }, 0);
          });
          break;
        // promise位于fulfilled状态时,直接执行onResolved
        case STATUS.RESOLVED:
          setTimeout(() => {
            try {
              const x = onResolved(this.value);
              resolvePromise(x, promise2, resolve, reject);
            } catch (err) {
              reject(err);
            }
          }, 0);
          break;
        // promise位于rejected状态时,直接执行onRejected
        case STATUS.REJECTED:
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolvePromise(x, promise2, resolve, reject);
            } catch (err) {
              reject(err);
            }
          }, 0);
          break;
      }
    });
    // 返回该promise
    return promise2;
  }

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

  // MyPromise.prototype.finally
  finally(onFinally) {
    return this.then(onFinally, onFinally);
  }

  // MyPromise.all
  static all(promises) {
    let resolvedCount = 0;
    const length = promises.length,
      result = new Array(length),
      resolvedCountAdd = (index, value, resolve) => {
        resolvedCount++;
        result[index] = value;
        if (resolvedCount === length) {
          resolve(result);
        }
      };
    return new MyPromise((resolve, reject) => {
      for (let i = 0; i < length; i++) {
        promises[i].then(
          (value) => {
            resolvedCountAdd(i, value, resolve);
          },
          (reason) => {
            reject(reason);
          }
        );
      }
    });
  }

  // MyPromise.any
  static any(promises) {
    let rejectedCount = 0;
    const length = promises.length,
      result = new Array(length),
      rejectedCountAdd = (index, reason, reject) => {
        rejectedCount++;
        result[index] = reason;
        if (rejectedCount === length) {
          reject(result);
        }
      };
    return new MyPromise((resolve, reject) => {
      for (let i = 0; i < length; i++) {
        promises[i].then(
          (value) => {
            resolve(value);
          },
          (reason) => {
            rejectedCountAdd(i, reason, reject);
          }
        );
      }
    });
  }

  // MyPromise.allSettled
  static allSettled(promises) {
    let processedCount = 0;
    const length = promises.length,
      result = new Array(length),
      processedCountAdd = (index, data, resolve) => {
        processedCount++;
        result[index] = data;
        if (processedCount === length) {
          resolve(result);
        }
      };
    return new MyPromise((resolve) => {
      for (let i = 0; i < length; i++) {
        promises[i].then(
          (value) => {
            processedCountAdd(i, value, resolve);
          },
          (reason) => {
            processedCountAdd(i, reason, resolve);
          }
        );
      }
    });
  }

  // MyPromise.race
  static race(promises) {
    const length = promises.length;
    return new MyPromise((resolve, reject) => {
      for (let i = 0; i < length; i++) {
        promises[i].then(
          (value) => {
            resolve(value);
          },
          (reason) => {
            reject(reason);
          }
        );
      }
    });
  }
  //  MyPromise.resolve
  static resolve(value = undefined) {
    // 如果不是对象,则直接返回resolve(value)
    if (!(value instanceof Object)) {
      return new MyPromise((resolve) => {
        resolve(value);
      });
    }
    // 如果是promise实例,则原封不动的返回
    if (value instanceof MyPromise) {
      return value;
    }
    // 如果是thenable的对象,则包装后返回,
    // 否则直接返回resolve(value)
    const then = value.then;
    if (typeof then === "function") {
      return new Promise(then.bind(value));
    } else {
      return new MyPromise((resolve) => {
        resolve(value);
      });
    }
  }

  // MyPromise.reject
  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    });
  }

  // 使用 promises-aplus-tests 进行测试
  static deferred() {
    const defer = {};
    defer.promise = new MyPromise((resolve, reject) => {
      defer.resolve = resolve;
      defer.reject = reject;
    });
    return defer;
  }
}

module.exports = MyPromise;

验证

新建文件MyPromise.js,复制以上代码到其中,再执行以下命令:

npm i promises-aplus-tests -g
promises-aplus-tests MyPromise.js

# ...
# 872 passing (18s)