节流Throttle的原理?运用场景?手写代码?

56 阅读2分钟

1. 节流Throttle的原理?

每隔n秒执行一次方法,第一次触发事件后,等待n秒后按照触发时的输入条件执行一次方法,n秒内的其他触发,不予理会。

2. 运用场景

浏览器的onresize()行为,用户疯狂的点击一个按钮的时候,总之就是一些重复性操作

3. 手写代码

分为两种方法,一种是时间戳,一种是定时器

时间戳:

let pre = 0;
function throttle(event,time){
  return function(...args){
    if(Date.now()-pre>time){
      event.apply(this,args)
      pre = Date.now();

    }
  }
}

定时器:

let timeID = null
function throttle(fn,wait){
  return function(){
    if(!timeID){  //这里的条件什么时候变false :在倒计时wait还没有结束的时候 继续输入,这个时候timer还没有重置为null,所以结果为false  不得不说定时器很牛
      timer = setTimeout(()=>{
        clearTimeout(timeID) 
       //不可以用ClearTimeOut代替timer=null 为什么呢 他只是重置定时器,并没有把timer重置为null
       //设置为null干什么? 为了在上一次的定时器倒计时结束之后清理掉上一次的定时器ID 这样的话 timer就为null,上面的if判断就成立了,下一次触发可以重新计数了
       timer = null
        fn.apply(this,arguments)
      },wait)
    }
  }
}

这两种方法经过我的实践,发现工作效果是有区别的:

时间戳的效果:假如应用在input输入框上,一定会执行第一次输入,也就是说如果输入框第一次输入一个1,不管后面输入什么,第一次执行都是输出1。而最后一次输入结束后,离上一次触发事件的时间<=冷却时间的话,就不会执行方法。所以我不推荐时间戳方法。

定时器:第一次触发事件后,如果输入一串字符,那么会输出延迟时间后文本框中的内容,而不是输入的第一个字符。且如果最后一次输入结束后,离上一次触发事件的时间<=冷却时间的话,还是会执行方法。

造成这两种区别在于时间戳执行代码没有延迟,是立即执行,也就是根据当时触发时候的文本框内容获取数据。定时器有延迟,所以定时器的等待时间结束后,执行回调,根据当前输入框里面的内容获取数据

所以在使用input输入框时,根据输入内容查询接口,使用定时器实现的throttle会更正确,因为时间戳这种方法会导致用户输入的关键词和查询到的数据对不上的情况发生,但是对比debounce来看,还是debounce更加适合这种情况,等用户停止输入后再获取数据。