丁鹿学堂:前端面试分享系列之手写promise(一)

69 阅读2分钟

从零开始手写promise(一)

上次总结了promise A+ 规范,其实js中的promise只是实现了这个规范。就像js这个语言实现了es的规范一个道理。

带着大家一起手写promise,让我们可以更透彻的理解promise。

今天分享第一步,实现一个工具函数,为后面手写promise服务。

一个是add方法,可以添加函数到队列里,一个是statrup方法,它从工具函数里面拿到函数去依次执行。

因为resove本身也是从函数队列里去拿出来函数执行。

实现一个container工具函数

再加一些需求,如果创建实例的时候添加一些特殊的字段,会有特殊的功能:

stopOnFalse:如果有一个回调函数返回false,则后续的函数不执行

    let p = container('stopOnFalse')
    let fn1 = function(){
      console.log(1)
      return false
    }
    let fn2 = function(){
      console.log(2)
    }
    p.add(fn1,fn2)
    p.startup() 

once:重复调用的话只执行第一次

    let p = container('once')
    let fn1 = function(){
      console.log(1)
      return false
    }
    let fn2 = function(){
      console.log(2)
    }
    p.add(fn1,fn2)
    p.startup()
    p.startup()

memory:实力化以后添加函数立即执行

    let p = container('memory')
    let fn1 = function(){
      console.log(1)
      return false
    }
    let fn2 = function(){
      console.log(2)
    }
    p.add(fn1,fn2)
    p.startup()
    p.add(function(){
      console.log(3)
    })

具体实现代码在这里:纯粹干货

let cache = {} // 缓存对象
let container = function(flags){
  flags = typeof flags === 'string' ? (cache[flags] || createFlags(flags)):extend({},flags)
  let carryOut = false
  let stack = []
  let memory = false
  let stackLen,stackPoint = 0
  let fire = function(data){
    let len = stack.length;
    let i = stackPoint || 0
    stackPoint = 0
    memory = flags.memory && data // flags.memory存在就把data 赋值给变量memory
    carryOut = true
    for(;i<len;i++){
      if(stack[i].apply(data[0],data[1]) === false && flags.stopOnFalse){
        break
      }
      
    }
  }
  let obj = {
    add:function(){
      (function(args){
        stackLen = stack.length
        Array.from(args).forEach(item=>{
          if(toString.call(item) === '[object Function]'){
            if(!obj.has(item)){
              stack.push(item)
            }
          }else{
            throw new Error('请正确传参数')
          }
        })
      })(arguments)
      if(memory){
        stackPoint = stackLen
        fire(memory)
      }
    },
    startBind(context,args){
      args = args || []
      args = [context,args]
      if(!flags.once || !carryOut){
        fire(args)
      }
    },
    startup(){
      obj.startBind(this,arguments)
    },
    has(fn){
      return stack.indexOf(fn) > -1
    }
  }
  return obj
}
// (flags.match(/\S+/g) 是根据空格去分割字符串为数组
function createFlags(flags){
 let res = {}
let arr = flags.match(/\S+/g) || []
arr.forEach(item =>{
  res[item] = true
})

 return res
}
function extend(to,from){
 for(let key in from){
  to[key] = from[key]
 }
 return to
}