Promise的实现(step by step)

闲来无事,对着阮一峰的《es6入门教程》中promise章节,仅仅观察其表象和特性,一步步实现了Promise这个黑箱子,实现了文中描述的大部分功能与特性,并且还将持续完善,权当磨练技术。

以下是较为完善的版本。

class _Promise {
  constructor(callback) {
    this.status = 'pending';
    this.funcArr = [];
    try {
      callback(params => {
        setTimeout(() => {
          if (this.status != 'pending') return;
          this.status = 'resolved';
          // result保存resolve传递的参数
          let result = params;
          if (result instanceof _Promise) {
            for (let i = 0; i < this.funcArr.length; i++) {
              const func = this.funcArr[i];
              if (func.type === 'suc') {
                result.then(func);
              } else {
                result.catch(func);
              }
            }
          } else if (result instanceof Error) {
            for (let i = 0; i < this.funcArr.length; i++) {
              const func = this.funcArr[i];
              if (func.type === 'fail') {
                try {
                  result = func(result);
                } catch (e) {
                  result = e;
                }
                const _p = _Promise.resolve(result);
                for (let j = i + 1; j < this.funcArr.length; j++) {
                  const func = this.funcArr[j];
                  if (func.type === 'suc') {
                    _p.then(func);
                  } else {
                    _p.catch(func);
                  }
                }
                break;
              }
            }
          } else {
            for (let i = 0; i < this.funcArr.length; i++) {
              const func = this.funcArr[i];
              if (func.type === 'suc') {
                try {
                  result = func(result);
                } catch (e) {
                  result = e;
                }
                const _p = _Promise.resolve(result);
                for (let j = i + 1; j < this.funcArr.length; j++) {
                  const func = this.funcArr[j];
                  if (func.type === 'suc') {
                    _p.then(func);
                  } else {
                    _p.catch(func);
                  }
                }
                break;
              }
            }
          }

        }, 0)
      }, params => {
        setTimeout(() => {
          if (this.status != 'pending') return;

          this.status = 'rejected';
          let result = params;
          if (result instanceof _Promise) {
            for (let i = 0; i < this.funcArr.length; i++) {
              const func = this.funcArr[i];
              if (func.type === 'suc') {
                result.then(func);
              } else {
                result.catch(func);
              }
            }
          } else {
            for (let i = 0; i < this.funcArr.length; i++) {
              const func = this.funcArr[i];
              if (func.type === 'fail') {
                try {
                  result = func(result);
                } catch (e) {
                  result = e;
                }
                const _p = _Promise.resolve(result);
                for (let j = i + 1; j < this.funcArr.length; j++) {
                  const func = this.funcArr[j];
                  if (func.type === 'suc') {
                    _p.then(func);
                  } else {
                    _p.catch(func);
                  }
                }
                break;
              }
            }
          }

        }, 0)
      })
    } catch (err) {
      setTimeout(() => {
        if (this.status != 'pending') return;
        this.status = 'rejected';
        let result = err;
        let hasCatch = false;

        for (let i = 0; i < this.funcArr.length; i++) {
          const func = this.funcArr[i];
          if (func.type === 'fail') {
            try {
              result = func(result);
            } catch (e) {
              result = e;
            }
            const _p = _Promise.resolve(result);
            for (let j = i + 1; j < this.funcArr.length; j++) {
              const func = this.funcArr[j];
              if (func.type === 'suc') {
                _p.then(func);
              } else {
                _p.catch(func);
              }
            }
            hasCatch = true;
            break;
          }
        }

        if (!hasCatch) {
          throw result;
        }

      }, 0)
    }

  }

  then(suc, fail) {
    if (typeof suc === 'function') {
      suc.type = 'suc';
      this.funcArr.push(suc);
    }
    if (typeof fail === 'function') {
      fail.type = 'fail';
      this.funcArr.push(fail);
    }

    return this;
  }

  catch(fail) {
    if (typeof fail === 'function') {
      fail.type = 'fail';
      this.funcArr.push(fail);
    }

    return this;
  }

  finally(callback) {
    this.then(() => {
      callback();
    }, () => {
      callback();
    });
    return this;
  }
}

_Promise.resolve = function (params) {
  if (params instanceof _Promise) {
    return params;
  } else {
    return new _Promise(resolve => {
      resolve(params);
    })
  }
}

_Promise.reject = function (params) {
  return new _Promise((resolve, reject) => {
    reject(params);
  })
}

_Promise.all = function (params) {
  return new _Promise((resolve, reject) => {
    let results = [];
    let count = 0;

    params.forEach((p, i) => {
      results[i] = null;
      _Promise.resolve(p).then(res => {
        results[i] = res;
        count++;
        if (count === results.length) {
          resolve(results);
        }
      }).catch(err => {
        reject(err);
      })
    })
  })
}

export default _Promise
复制代码

因为写代码本身是个思维很跳跃的过程,所以具体的实现步骤就不描述了,但是我的github仓库里保留了每一个小里程碑的源码记录,如果有兴趣可以查看,这样就能大概还原整个编码过程的心路历程。

github仓库--Promise的简单实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值