沉浸式手写promise(渐进式之知其所以然)


在这里插入图片描述

1.我们先写一个理论上可行的版本

代码分析

  • 1.我们用classpromise写成一个类
  • 2.构造函数参数是一个func,我们在内部需要调用resolvereject两个方法
  • 3.class里面我们要写resolvereject两个方法
  • 4.promise的三个状态我们static出来当作常量在,在构造函数中加入statusresult
  • 5.在resolvereject方法中加入status的办法,并将参数result赋值给result

class Commitment {
  static PENDING = '待定'
  static FULFILED = '成功'
  static REJECTED = '拒绝'
  constructor(func) {
    this.status = Commitment.PENDING
    this.result = null
    func(this.resolve, this.reject)
  }
  resolve (result) {
    if (this.status === Commitment.PENDING) {
      this.status = Commitment.FULFILED
      this.result = result
    }
  }
  reject (result) {
    if (this.status === Commitment.PENDING) {
      this.status = Commitment.REJECTED
      this.result = result
    }
  }
}

测试竟然报错

let commitment = new Commitment((res, rej) => {
  res('这次一定')
})

在这里插入图片描述

new之后this指针改变,使用bind改变this指针

func(this.resolve.bind(this), this.reject.bind(this))

2.加上then()

  then (onFULFILED, onREJECTED) {
    if (this.status === Commitment.FULFILED) {
      onFULFILED(this.result)
    }
    if (this.status === Commitment.REJECTED) {
      onREJECTED(this.result)
    }
  }

简单测试通过

let commitment = new Commitment((res, rej) => {
  res('这次一定')
})
commitment.then(
  result => { console.log(result); },
  result => { console.log(result.message); }
)

3.改进一些bug

构造函数调用函数使用try,catch

有的时候在构造的时候也许会报错,promise会直接输出错误信息,所以我们这里

  • 要写成trycatch,然后调用reject返回信息
  • 这里的reject不用bind,因为是在创建实例前调用的
    // func(this.resolve.bind(this), this.reject.bind(this))
    try {
      func(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }

then传入不是函数报错

commitment.then(
  undefined,
  // result => { console.log(result); },
  result => { console.log(result.message); }
)

在这里插入图片描述

我们用条件运算符改写then()

  then (onFULFILED, onREJECTED) {
    onFULFILED = typeof onFULFILED === 'function' ? onFULFILED : () => { }
    onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }
    if (this.status === Commitment.FULFILED) {
      onFULFILED(this.result)
    }
    if (this.status === Commitment.REJECTED) {
      onREJECTED(this.result)
    }
  }

4.完成promise的异步功能

我们先来测试一下当前的异步结果

console.log('first');
let commitment = new Commitment((res, rej) => {
  console.log('second');
  res('这次一定')
})
commitment.then(
  result => { console.log(result); },
  result => { console.log(result.message); }
)
console.log('third');

  • 结果显然很不异步
first
second
这次一定
third

在then()方法中使用setTimeout调用方法

  then (onFULFILED, onREJECTED) {
    onFULFILED = typeof onFULFILED === 'function' ? onFULFILED : () => { }
    onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }
    if (this.status === Commitment.FULFILED) {
      setTimeout(() => {
        onFULFILED(this.result)
      })
    }
    if (this.status === Commitment.REJECTED) {
      setTimeout(() => {
        onREJECTED(this.result)
      })
    }
  }

5.回调保存

测试:如果在promise里面写一个setTimeout?

  • 结果我们没有resolve输出了
console.log('first');
let commitment = new Commitment((res, rej) => {
  console.log('second');
  setTimeout(() => {
    res('这次一定')
    console.log('fourth');
  })

})
commitment.then(
  result => { console.log(result); },
  result => { console.log(result.message); }
)
console.log('third');

  • 输入结果
first
second
third
fourth

分析与改进

  • 因为setTimeoutthen第一次进入的时候,我们的状态是pending所以没有执行函数
  • 所以,我在pending状态的时候,把回调函数存起来就可以了(之后resolve的时候再调用回调即可)
   if (this.status === Commitment.PENDING) {
      this.resolveCallbacks.push(onFULFILED)
      this.rejectCallbacks.push(onREJECTED)
    }
  • 之后改写resolvereject方法
    • 注意:这里也要用setTimeout
  resolve (result) {
    setTimeout(() => {
      if (this.status === Commitment.PENDING) {
        this.status = Commitment.FULFILED
        this.result = result
        this.resolveCallbacks.forEach(callback => {
          callback(result)
        })
      }
    })
  }

6.链式调用

测试:我们连续使用两次then()

let commitment = new Commitment((res, rej) => {
  res('这次一定')
})
commitment.then(
  result => { console.log(result); },
  result => { console.log(result.message); }
).then(
  result => { console.log(result); },
  result => { console.log(result.message); }
)

报错如下
在这里插入图片描述

then中返回一个Commitment对象

 then (onFULFILED, onREJECTED) {
    return new Commitment((resolve, reject) => {
      onFULFILED = typeof onFULFILED === 'function' ? onFULFILED : () => { }
      onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }
      if (this.status === Commitment.PENDING) {
        this.resolveCallbacks.push(onFULFILED)
        this.rejectCallbacks.push(onREJECTED)
      }
      if (this.status === Commitment.FULFILED) {
        setTimeout(() => {
          onFULFILED(this.result)
        })
      }
      if (this.status === Commitment.REJECTED) {
        setTimeout(() => {
          onREJECTED(this.result)
        })
      }
    })
  }

汇总完整代码

class Commitment {
  static PENDING = '待定'
  static FULFILED = '成功'
  static REJECTED = '拒绝'
  constructor(func) {
    this.status = Commitment.PENDING
    this.result = null
    this.resolveCallbacks = []
    this.rejectCallbacks = []
    // func(this.resolve.bind(this), this.reject.bind(this))
    try {
      func(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }
  }
  resolve (result) {
    setTimeout(() => {
      if (this.status === Commitment.PENDING) {
        this.status = Commitment.FULFILED
        this.result = result
        this.resolveCallbacks.forEach(callback => {
          callback(result)
        })
      }
    })
  }
  reject (result) {
    setTimeout(() => {
      if (this.status === Commitment.PENDING) {
        this.status = Commitment.REJECTED
        this.result = result
        this.rejectCallbacks.forEach(callback => {
          callback(result)
        })
      }
    });
  }
  then (onFULFILED, onREJECTED) {
    return new Commitment((resolve, reject) => {
      onFULFILED = typeof onFULFILED === 'function' ? onFULFILED : () => { }
      onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }
      if (this.status === Commitment.PENDING) {
        this.resolveCallbacks.push(onFULFILED)
        this.rejectCallbacks.push(onREJECTED)
      }
      if (this.status === Commitment.FULFILED) {
        setTimeout(() => {
          onFULFILED(this.result)
        })
      }
      if (this.status === Commitment.REJECTED) {
        setTimeout(() => {
          onREJECTED(this.result)
        })
      }
    })
  }
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值