Promise

151 阅读3分钟
const PENDING = 'pending'; //等待
const FULFILLED = 'fulfilled'; //失败
const REJECTED = 'rejected'; //成功

class MyPromise {
  constructor(executor) {
    try {
      executor(this.resolve, this.reject);
    } catch (error) {
      //捕获执行器中的错误
      this.reject(error);
    }
  }
  status = PENDING; //默认等待
  value = undefined; //成功之后的值
  reason = undefined; //失败之后的原因
  successCallback = []; //成功回调
  failCallback = []; //失败回调

  //定义成箭头函数为了保证this指向Promise本身
  resolve = (value) => {
    if (this.status !== PENDING) return; //如果状态不是pending,阻止程序向下执行
    this.status = FULFILLED; //将状态改为成功
    this.value = value; //保存成功之后的值

    // 判断成功回调是否存在,存在的话就调用(处理异步的情况)
    // this.successCallback && this.successCallback(this.value);
    while (this.successCallback.length) this.successCallback.shift()();
  };

  reject = (reason) => {
    if (this.status !== PENDING) return; //如果状态不是pending,阻止程序向下执行
    this.status = REJECTED; //将状态改为失败
    this.reason = reason; //保存失败的原因

    // 判断失败回调是否存在,存在的话就调用(处理异步的情况)
    // this.failCallback && this.failCallback(this.reason);
    while (this.failCallback.length) this.failCallback.shift()();
  };

  then(successCallback, failCallback) {
    //处理参数不传的情况(参数可选的情况)
    successCallback = successCallback ? successCallback : (value) => value;
    failCallback = failCallback
      ? failCallback
      : (reason) => {
          throw reason;
        };

    let promise2 = new MyPromise((resolve, reject) => {
      // 判断状态
      if (this.status === FULFILLED) {
        setTimeout(() => {
          //让这块代码变成异步的,然后才能拿到promise2
          try {
            let x = successCallback(this.value);
            resolvePromise(promise2, x, resolve, reject); //将then的返回值传递给下一个then
          } catch (error) {
            //捕获then中的错误然后传递给下一个rejecte
            reject(error);
          }
        }, 0);
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          //让这块代码变成异步的,然后才能拿到promise2
          try {
            let x = failCallback(this.reason);
            resolvePromise(promise2, x, resolve, reject); //将then的返回值传递给下一个then
          } catch (error) {
            //捕获then中的错误然后传递给下一个rejecte
            reject(error);
          }
        }, 0);
      } else {
        //等待(处理异步的情况)
        // 将成功和失败的回调保存起来
        this.successCallback.push(() => {
          setTimeout(() => {
            //让这块代码变成异步的,然后才能拿到promise2
            try {
              let x = successCallback(this.value);
              resolvePromise(promise2, x, resolve, reject); //将then的返回值传递给下一个then
            } catch (error) {
              //捕获then中的错误然后传递给下一个rejecte
              reject(error);
            }
          }, 0);
        });
        this.failCallback.push(() => {
          setTimeout(() => {
            //让这块代码变成异步的,然后才能拿到promise2
            try {
              let x = failCallback(this.reason);
              resolvePromise(promise2, x, resolve, reject); //将then的返回值传递给下一个then
            } catch (error) {
              //捕获then中的错误然后传递给下一个rejecte
              reject(error);
            }
          }, 0);
        });
      }
    });
    return promise2;
  }

  finally(callback) {
    return this.then(
      (value) => {
        return MyPromise.resolve(callback()).then(() => value);
      },
      (reason) => {
        return MyPromise.resolve(callback()).then(() => {
          throw reason;
        });
      }
    );
  }

  catch(failCallback) {
    return this.then(undefined, failCallback);
  }

  static all(array) {
    let result = [];
    let index = 0;
    return new MyPromise((resolve, reject) => {
      function addData(key, value) {
        result[key] = value;
        index++;
        if (index === array.length) {
          //保证array中的每一项都执行完
          resolve(result);
        }
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise) {
          current.then(
            (value) => addData(i, value),
            (reason) => reject(reason)
          );
        } else {
          addData(i, array[i]);
        }
      }
    });
  }

  static resolve(value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise((resolve) => resolve(value));
  }

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

  static race(array) {
    return new MyPromise((resolve, reject) => {
      array.forEach((p) => {
        MyPromise.resolve(p).then(
          (value) => {
            resolve(value);
          },
          (reason) => {
            reject(reason);
          }
        );
      });
    });
  }

  static allSettled(array) {
    let result = [];
    return new MyPromise((resolve, reject) => {
      array.forEach((p, i) => {
        MyPromise.resolve(p).then(
          (value) => {
            result.push({
              status: 'fulfilled',
              value: value,
            });
            if (result.length === array.length) {
              resolve(result);
            }
          },
          (reason) => {
            result.push({
              status: 'rejected',
              reason: reason,
            });
            if (result.length === array.length) {
              resolve(result);
            }
          }
        );
      });
    });
  }

  static any(array) {
    let index = 0;
    return new MyPromise((resolve, reject) => {
      if (array.length === 0) return;
      array.forEach((p, i) => {
        MyPromise.resolve(p).then(
          (value) => {
            resolve(value);
          },
          (reason) => {
            index++;
            if (index === array.length) {
              reject(new AggregateError('All promises were rejected'));
            }
          }
        );
      });
    });
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
  /*
    1.判断x的值是普通值还是promise对象
    2.如果是普通值,直接调用resolve
    3.如果是promise对象,查看promise对象返回的结果
    4.再根据promise对象返回的结果,决定是调用resolve,还是reject
    */
  if (x instanceof MyPromise) {
    //promise对象
    //x.then(value => resolve(value), reason => reject(reason))
    x.then(resolve, reject);
  } else {
    //普通值
    resolve(x);
  }
}