实现一个Promise

Promise的大概功能

  • then 接收两个参数,参数1是成功的回调,参数2是失败的回调
  • catch 接收一个参数,失败的回调 
  • finally 接收一个参数,成功/失败都会触发
  • resolve 接收一个参数
  • reject 接收一个参数
  • all 接收一个数组 全部成功或一个失败则结束
  • race 接收一个数组 一个完成则结束
  • any 接收一个有length可遍历的数据,当里面有一个成功则结束,如果一个成功都没有则报错
  • allSettled 接收一个有length可遍历的数据,当里面全部完成则结束,错误不会停止

Promise规范

Promise本质是一个状态机,且状态只能为以下三种:Pending(等待态)Fulfilled(执行态)Rejected(拒绝态),状态的变更是单向的,只能从Pending -> Fulfilled 或 Pending -> Rejected,状态变更不可逆

class IPromise<T> {
  // IPromise的状态,等待中,成功,失败
  status: 'pending' | 'fulfilled' | 'rejected';
  // 存储resolve的队列
  resolveQueue: Array<((value?: T) => any)>;
  // 存储reject的队列
  rejectQueue: Array<((reason: any) => any)>;
  // 给then/catch的数据
  _value: T | undefined;
  // 接收一个函数参数,两个入参是resolve 和 reject
  constructor(executor: (reslove: (value: T) => void, reject: (reason: unknown) => void) => void) {
    this.resolveQueue = [];
    this.rejectQueue = [];
    this.status = 'pending';
    this._value = undefined;
    // 定义一个this,否则resolve/reject不是箭头函数拿不到this
    let _this = this;
    // 定义resolve
    let _resolve = function (_props?: T) {
      // 只有状态是pending才可以进行
      if (_this.status !== 'pending') return;
      // 改变状态
      _this.status = 'fulfilled';
      // 存储数据
      _this._value = _props;
      // 判断是否有成功的回调
      while (_this.resolveQueue?.length) {
        const callback = _this.resolveQueue.shift();
        callback?.(_props);
      }
    };

    // 定义reject
    let _reject = function (_props: any) {
      if (_this.status !== 'pending') return;
      _this.status = 'rejected';
      _this._value = _props;
      while (_this.rejectQueue?.length) {
        const callback = _this.rejectQueue.shift();
        callback?.(_props);
      }
    };
    // 调用入参 传入resolve和reject
    try {
      executor(_resolve, _reject);
    } catch (error) {
      // 如果错误直接执行reject
      _reject(error);
    }
  }

  /**
   * @then 传入两个参数
  */
  then(resolveFn, rejectFn) {
    // 给成功队列添加回调
    this.resolveQueue.push(resolveFn);
    // 给失败队列添加回调
    typeof rejectFn === 'function' && this.rejectQueue.push(rejectFn);
  }
}

到这里就完成了一个最基础的Promise,但是这里我们还不可以链式调用,并且只能处理异步,当Promise是同步时目前是处理不了的,js执行机制从上到下,Promise里面如果是同步,成功和失败的队列则为空,我们的Promise的回调没有再return一个Promise出去所以不能链式,接下来继续完善一下

then的链式调用和处理同步

要想链式调用则需要Promise的then再return一个Promise出去才可以实现,想要处理同步则需要在then里面判断一下当前状态,现在我们继续修改then的代码

/**
 * @then { then传入两个参数,参数1是成功的回调,参数2是失败的 }
*/
then(resolveFn?: (value: T) => any, rejectFn?: (reason: any) => any) {
  // 判断参数是否为函数,如果不是函数会把IPromise的数据返回出去
  typeof resolveFn === 'function' ? null : resolveFn = value => value;
  typeof rejectFn === 'function' ? null : rejectFn = value => value;

  /**
   * @返回一个IPromise链式调用
  */
  return new IPromise((resolve, reject) => {
    /**
     * @给then的参数包装的执行一下判断返回值是否为IPromise
    */
    const fulfilledFn = (value) => {
      const res = resolveFn?.(value);
      res instanceof IPromise ? res?.then(resolve, reject) : resolve(res);
    }

    const rejectedFn = (error) => {
      const res = rejectFn?.(error);
      res instanceof IPromise ? res.then(resolve, reject) : reject(res);
    }

    // 判断IPromise的状态
    switch (this.status) {
      case 'pending':
        // Promise内部是异步,这里为等待中则给队列中添加任务
        this.resolveQueue.push(fulfilledFn);
        this.rejectQueue.push(rejectedFn);
        break;
      case 'fulfilled':
        // 如果Promise内部是同步完成则这里直接调用then里面的成功回调
        fulfilledFn(this._value);
        break;
      case 'rejected':
        // 如果Promise内部是同步完成并且then的失败回调为function则直接调用
        rejectedFn(this._value);
        break;
      default:
        break;
    }

  })
}

现在我们的Promise就可以处理同步与异步,并且可以链式调用了,接下来我们再完成.catch的部分

.catch 失败回调

完成了then方法,其他catch方法就非常简单,因为then的第二个参数也是失败的回调,我们在这里只需调用的return一个then就好了

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

接下来继续完成.finally的部分

.finally 全部的回调

.finally 不管Promise是成功还是失败都会触发,并且finally拿不到成功/错误的信息,并且finally内部如果return了一个Promise,这个Promise是成功的状态则下一个then拿到的当前Promise的值,如果是失败的状态,则下一个then的失败回调拿到的是finally里面这个Promise的reject值

如下图

 了解了finally的功能我们继续往下写

finally(callback) {
  const fun = (value) => {
    // finally传入的是否为函数
    const res = typeof callback === 'function' && callback?.();
    // 如果finally的回调返回一个IPromise则根据这个IPromise的状态给值,
    if (res instanceof IPromise) {
      return res?.status === 'fulfilled' ? value : res?.value;
    } else {
      // 如果finally回调返回的不是IPromise,则判断当前IPromise的状态为失败则后续的也是失败,否则为成功
      return this.status === 'rejected' ? Promise.reject(value) : value;
    }
  };
  // 调用then传入一个成功一个失败
  return this.then(
    (value) => fun(value),
    // promise<200> 
    (error) => fun(error),
  )
}

finally只要Promise完成就会触发,所以这里咱们需要给then里面添加两个回调

这里我们包装一下finally的回调,因为finally的回调拿不到值所以直接直接调用,如果该回调返回了一个Promise,判断该Promise的状态,如果是成功则把当前Promise的值返回给下一个Promise,否则把回调的Promise值给下一个,当回调非函数或者没有返回Promise时则判断当前promise的状态,如果是失败则返回一个失败,这里用到了Promise.reject,快速返回一个失败的Promise,后续我们会补上该方法

.resolve 快速的返回一个Promise

当.resolve的值为Promise时,该Promise一个为失败则失败

static resolve(value) {
  // 如果参数为Promise则直接返回这个Promise
  if (value instanceof IPromise) return value
  // 如果参数飞Promise则创建一个Promise并且参数当值调用成功
  return new IPromise(_resolve => _resolve(value));
};

.reject 返回一个失败的Promise

static reject(value) {
  // reject不去管参数的是什么类型,直接返回一个失败的Promise
  return new IPromise((resolve, reject) => reject(value));
};

.all 当数组里所有参数都执行完成触发/失败一个也触发

all接收一个数组,当数组里面全部完成则结果then的回调拿到一个数组

当里面有一个失败则走到失败回调

static all(callbackArr: IPromise<any>[]) {
  // 记录有几个完成
  let resultIndex = 0;
  // 记录对应下标的结果
  let result = [] as any[];

  return new IPromise((resolve, reject) => {
    // 如果参数不是数组直接报错
    if (callbackArr instanceof Array) {
      callbackArr?.some((item, index) => {
        // 如果不是Promise则直接添加结果
        if (item instanceof IPromise) {
          item
          .then(res => {
            result[index] = res; // 给对应下标添加结果
            resultIndex++; // 完成数++
            // 判断完成数量是否等于总数
            if (resultIndex === callbackArr?.length) {
              return resolve(result);
            }
          }, err => {
            return reject(err);
          })
        } else {
          result[index] = item;
          resultIndex++;
          if (resultIndex === callbackArr?.length) {
            return resolve(result);
          }
        }
      })
    } else {
      reject(`TypeError: ${typeof callbackArr} ${callbackArr} is not iterable (cannot read property Symbol(Symbol.iterator))`)
    }
  })

}

.race 竞速,有一个完成则结束

race接收一个数组,当数组里面有一个完成则结束,返回完成的结果

static race(callbackArr: IPromise<any>[]) {
  return new IPromise((resolve, reject) => {
    // 如果参数不是数组直接报错
    if (callbackArr instanceof Array) {
      callbackArr?.some((item, index) => {
        // 如果不是Promise则直接添加结果
        if (item instanceof IPromise) {
          item
          .then(res => {
            return resolve(res);
          }, err => {
            return reject(err);
          })
        } else {
          return resolve(item);
        }
      })
    } else {
      reject(`TypeError: ${typeof callbackArr} ${callbackArr} is not iterable (cannot read property Symbol(Symbol.iterator))`)
    }
  })
}

代码上只需要把all的那些结果总数,结果数组去掉,一个完成直接结束调该Promise

2023 - 03 - 09 补充 start

.any 任意一个成功则结束,race是任意一个完成则结束

 入参是一个有length可遍历的类型,所以这里使用for循环,如果循环项非Promise/Promise.then则直接resolve,如果没有一个resolve则会自动到reject

用then接收,如果是成功则return 该值,否则return一个Promise的错误

/**
 * @any 任意一个成功则返回
*/
static any(promiseArr) {
  if (typeof promiseArr.length === 'number') {
    return new IPromise((resolve, reject) => {
      for (let i = 0; i < promiseArr.length; i++) {
        if (promiseArr[i] instanceof IPromise) {
          promiseArr[i]
            .then(res => {
              return resolve(res);
            })
        } else {
          // 如果当前值不是Promise则直接成功
          return resolve(promiseArr[i]);
        }

      }
    })
      // 拿到当前Promise的回调,如果走then则代表完成直接把值抛出去
      .then(res => {
        return res;
      }, () => {
        // 如果catch则代表所有的promise都是rejected
        return Promise.reject('AggregateError: All promises were rejected');
      })
  } else {
    return IPromise.reject(`TypeError: ${typeof promiseArr} ${promiseArr} is not iterable (cannot read property Symbol(Symbol.iterator)) at IPromise.allSettled`)
  }
}

 

.allSettled 所有的完成则结束,all是所有的成功/有一个失败则结束

入参是一个有length可遍历的类型,所以这里使用for循环,如果循环项非Promise/Promise.then则给result添加对应下标添加数据,rindex++,判断是否为最后一个

/**
 * @allSettled 当数组里的promise全部执行完成返回结果,中途报错不会影响结果
*/
static allSettled(promiseArr: IPromise<any>[]) {
  // 有几个已执行
  let rindex = 0;
  // promise对应的结果
  let result = [] as any[];

  // return一个Promise
  return new IPromise((resolve, reject) => {
    // 封装一个方法,参数1是结果,参数2是当前下标,参数3可选的一个状态,默认为fulfilled成功
    function pushRes(value, index, type?: 'rejected') {
      result[index] = {
        type: type || 'fulfilled',
        value: value
      };
      rindex++;
      // 判断当前是否全部执行完成
      if (rindex === promiseArr?.length) {
        resolve(result);
      }
    };
    if (typeof promiseArr.length === 'number') {
      for (let i = 0; i < promiseArr.length; i++) {
        if (promiseArr[i] instanceof IPromise) {
          promiseArr[i]
            .then(res => {
              pushRes(res, i);
            }, err => {
              pushRes(err, i, 'rejected');
            })
        } else {
          pushRes(promiseArr[i], i);
        }
      }
    } else {
      reject(`TypeError: ${typeof promiseArr} ${promiseArr} is not iterable (cannot read property Symbol(Symbol.iterator)) at IPromise.allSettled`)
    }
  })
}

2023 - 03 - 09 补充 end

到这里我们的Promise就完成了,下面我上一下全量代码

class IPromise<T> {
  // IPromise的状态,等待中,成功,失败
  status: 'pending' | 'fulfilled' | 'rejected';
  // 存储resolve的函数
  resolveQueue: Array<((value?: T) => any)>;
  // 存储reject的函数
  rejectQueue: Array<((reason: any) => any)>;
  // 给then/catch的数据
  _value: T | undefined;
  // 接收一个函数参数,两个入参是resolve 和 reject
  constructor(executor: (reslove: (value: T) => void, reject: (reason: unknown) => void) => void) {
    this.resolveQueue = [];
    this.rejectQueue = [];
    this.status = 'pending';
    this._value = undefined;
    // 定义一个this,否则resolve等不是箭头函数拿不到this
    let _this = this;
    // 定义resolve
    let _resolve = function (_props?: T) {
      if (_this.status !== 'pending') return;
      _this.status = 'fulfilled';
      _this._value = _props;
      while (_this.resolveQueue?.length) {
        const callback = _this.resolveQueue.shift();
        callback?.(_props);
      }
    };

    // 定义reject
    let _reject = function (_props: any) {
      if (_this.status !== 'pending') return;
      _this.status = 'rejected';
      _this._value = _props;
      while (_this.rejectQueue?.length) {
        const callback = _this.rejectQueue.shift();
        callback?.(_props);
      }
    };
    // 调用入参
    try {
      executor(_resolve, _reject);
    } catch (error) {
      // 如果错误直接执行reject
      _reject(error);
    }
  }

  /**
   * @then { then传入两个参数,参数1是成功的回调,参数2是失败的 }
  */
  then(resolveFn?: (value: T) => any, rejectFn?: (reason: any) => any) {
    // 判断参数是否为函数,如果不是函数会把IPromise的数据返回出去
    typeof resolveFn === 'function' ? null : resolveFn = value => value;
    typeof rejectFn === 'function' ? null : rejectFn = value => value;

    /**
     * @返回一个IPromise链式调用
    */
    return new IPromise((resolve, reject) => {
      /**
       * @给then的参数包装的执行一下判断返回值是否为IPromise
      */
      const fulfilledFn = (value) => {
        const res = resolveFn?.(value);
        res instanceof IPromise ? res?.then(resolve, reject) : resolve(res);
      }

      const rejectedFn = (error) => {
        const res = rejectFn?.(error);
        res instanceof IPromise ? res.then(resolve, reject) : reject(res);
      }

      // 判断IPromise的状态
      switch (this.status) {
        case 'pending':
          // Promise内部是异步,这里为等待中则给队列中添加任务
          this.resolveQueue.push(fulfilledFn);
          this.rejectQueue.push(rejectedFn);
          break;
        case 'fulfilled':
          // 如果Promise内部是同步完成则这里直接调用then里面的成功回调
          fulfilledFn(this._value);
          break;
        case 'rejected':
          // 如果Promise内部是同步完成并且then的失败回调为function则直接调用
          rejectedFn(this._value);
          break;
        default:
          break;
      }

    })
  }

  /**
   * @catch { 错误的回调 }
  */
  catch(rejectFn) {
    /**
     * @直接调用then传入一个undefined和一个catch的回调
    */
    return this.then(undefined, rejectFn);
  }

  /**
   * @finally { 回调不管成功还是错误 }
  */
  finally(callback?: any) {
    const fun = (value) => {
      const res = typeof callback === 'function' && callback?.();
      // 如果finally的回调返回一个IPromise则根据这个IPromise的状态给值,
      if (res instanceof IPromise) {
        return res?.status === 'fulfilled' ? value : res?._value;
      } else {
        // 如果finally回调返回的不是IPromise,则判断当前IPromise的状态为失败则后续的也是失败,否则为成功
        return this.status === 'rejected' ? IPromise.reject(value) : value;
      }
    };
    // 调用then传入一个成功一个失败
    return this.then(
      (value) => fun(value),
      // promise<200> 
      (error) => fun(error),
    )
  }

  /**
   * @resolve 返回一个IPromise实例
   * */
  static resolve<R>(value?: R | IPromise<R>): IPromise<R> {
    // resolve传入一个参数,返回一个promise,如果该参数为promise则直接返回
    if (value instanceof IPromise) return value;
    return new IPromise((resolve) => resolve(value as R));
  };

  /**
   * @reject 返回一个失败的IPromise实例
   * */
  // IPromise.reject();
  static reject<R>(value: R): IPromise<R> {
    // reject传入一个参数,返回promise,不管参数的类型
    return new IPromise((resolve, reject) => reject(value));
  };

  /**
   * @all 当数组里的promise全部执行完成或者有一个报错则结束
  */
  static all(promiseArr: IPromise<any>[]) {
    // 有几个已执行
    let rindex = 0;
    // promise对应的结果
    let result = [] as any[];

    // return一个Promise
    return new IPromise((resolve, reject) => {
      // 如果入参不是数组则直接reject报错
      if (promiseArr instanceof Array) {
        promiseArr?.forEach((item, index) => {
          // 如果不是Promise则直接给对应位置添加返回值
          if (item instanceof IPromise) {
            item
              .then(res => {
                result[index] = res;
                rindex++;
                // 判断当前是否全部执行完成
                if (rindex === promiseArr?.length) {
                  resolve(result);
                }
              }, err => {
                reject(err);
              })
          } else {
            result[index] = item;
            rindex++;
            if (rindex === promiseArr?.length) {
              resolve(result);
            }
          }
        })
      } else {
        reject(`TypeError: ${typeof promiseArr} ${promiseArr} is not iterable (cannot read property Symbol(Symbol.iterator))`)
      }
    })
  }

  /**
   * @race 当数组里的promise有一个完成则结束
  */
  static race(promiseArr: IPromise<any>[]) {
    return new IPromise((resolve, reject) => {
      // 如果入参不是数组则直接reject报错
      if (promiseArr instanceof Array) {
        promiseArr?.some((item, index) => {
          // 如果不是Promise则直接给对应位置添加返回值
          if (item instanceof IPromise) {
            item
              .then(res => {
                return resolve(res);
              }, err => {
                return reject(err);
              })
          } else {
            return resolve(item);
          }
        })
      } else {
        reject(`TypeError: ${typeof promiseArr} ${promiseArr} is not iterable (cannot read property Symbol(Symbol.iterator))`)
      }
    })
  }

  /**
   * @any 任意一个成功则返回
  */
  static any(promiseArr) {
    if (typeof promiseArr.length === 'number') {
      return new IPromise((resolve, reject) => {
        for (let i = 0; i < promiseArr.length; i++) {
          if (promiseArr[i] instanceof IPromise) {
            promiseArr[i]
              .then(res => {
                return resolve(res);
              })
          } else {
            // 如果当前值不是Promise则直接成功
            return resolve(promiseArr[i]);
          }

        }
      })
        // 拿到当前Promise的回调,如果走then则代表完成直接把值抛出去
        .then(res => {
          return res;
        }, () => {
          // 如果catch则代表所有的promise都是rejected
          return Promise.reject('AggregateError: All promises were rejected');
        })
    } else {
      return IPromise.reject(`TypeError: ${typeof promiseArr} ${promiseArr} is not iterable (cannot read property Symbol(Symbol.iterator)) at IPromise.allSettled`)
    }
  }

  /**
   * @allSettled 当数组里的promise全部执行完成返回结果,中途报错不会影响结果
  */
  static allSettled(promiseArr: IPromise<any>[]) {
    // 有几个已执行
    let rindex = 0;
    // promise对应的结果
    let result = [] as any[];

    // return一个Promise
    return new IPromise((resolve, reject) => {
      // 封装一个方法,参数1是结果,参数2是当前下标,参数3可选的一个状态,默认为fulfilled成功
      function pushRes(value, index, type?: 'rejected') {
        result[index] = {
          type: type || 'fulfilled',
          value: value
        };
        rindex++;
        // 判断当前是否全部执行完成
        if (rindex === promiseArr?.length) {
          resolve(result);
        }
      };
      if (typeof promiseArr.length === 'number') {
        for (let i = 0; i < promiseArr.length; i++) {
          if (promiseArr[i] instanceof IPromise) {
            promiseArr[i]
              .then(res => {
                pushRes(res, i);
              }, err => {
                pushRes(err, i, 'rejected');
              })
          } else {
            pushRes(promiseArr[i], i);
          }
        }
      } else {
        reject(`TypeError: ${typeof promiseArr} ${promiseArr} is not iterable (cannot read property Symbol(Symbol.iterator)) at IPromise.allSettled`)
      }
    })
  }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值