丁鹿学堂:前端面试进阶系列之手写promise(二)

38 阅读2分钟
手写promise2

前面打好了基础,现在就开始手写promise。我们定义一个Promise函数。

定义一个二维数组,用于记录异步操作的信息。包括信息,状态等。

定义返回的对象chain,定义全局的state状态

protect 是绑定状态,成功和失败的回调才可以改变,所以不能直接绑定到返回的对象chain上。

  let tuples = [
    ["resolve",'done',container('once memory'),'resolved'],
    ["reject",'fail',container('once memory'),'rejected'],
  ]
  let state = 'pending'
  let chain = {} //promise返回的是一个对象
   let protect = {}

我们遍历这个数组,去获取container这个函数容器,得到的是两个外形一样的对象,但是其实他们是完全不一样的两个功能,一个是处理成功的,一个是处理失败的。

tuple【2】 其实就是这个容器。

  tuples.forEach((tuple,i)=>{
    let list = tuple[2]
    console.log(list)
  })

我们通过tuple【3】 去获取回调执行的状态。这里下标写死是没问题的,因为这个二维数组是我们定义的。 如果有状态,不管是成功还是失败,我们都往容器里去添加一个回调。在这个回调里我们可以进行状态的改变。 同时给返回的chain对象上添加一些方法,比如then等。

list.add 就是一个语法糖,我们通过done或者fail的调用,去向容器中添加成功或者失败的回调函数,

  tuples.forEach((tuple,i)=>{
    let list = tuple[2]
    let stateString = tuple[3]
    if(stateString){
      list.add(function(){
        state = stateString
      })
    }
    chain[tuple[1]] = list.add
  })

我们还要给返回的对象上去绑定状态。因为我们知道promise的状态确定以后就无法改变。而且只有异步操作的结果可以改变这个状态。所以在函数内部定义一个对象去绑定状态(就是上面定义的protect)

  tuples.forEach((tuple,i)=>{
    let list = tuple[2]
    let stateString = tuple[3]
    if(stateString){
      list.add(function(){
        state = stateString
      })
    }
    chain[tuple[1]] = list.add
    protect[tuple[0]] = function(){
      protect[tuple[0]+'Bind'](this,arguments)
    }
    protect[tuple[0]+'Bind'] = list.startBind
  })

整体的一个雏形就出来了:

function Promise(func){
  let tuples = [
    ["resolve",'done',container('once memory'),'resolved'],
    ["reject",'fail',container('once memory'),'rejected'],
  ]
  let state = 'pending'
  let protect = {}
  let chain = {} //promise返回的是一个对象
  tuples.forEach((tuple,i)=>{
    let list = tuple[2]
    let stateString = tuple[3]
    if(stateString){
      list.add(function(){
        state = stateString
      })
    }
    chain[tuple[1]] = list.add
    protect[tuple[0]] = function(){
      protect[tuple[0]+'Bind'](this,arguments)
    }
    protect[tuple[0]+'Bind'] = list.startBind
  })
  if(func){
    func.call(chain,protect['resolve'],protect['reject'])
  }
  return chain
}