js-节流的实现

67 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第28天,点击查看活动详情

前言

我们要实现节流首先要知道节流是什么?节流就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率

有一个场景,有一个div,设置了draggable属性为true,是可以拖动的,然后js代码里获取div元素并监听它的拖拽事件,拖拽的过程中并打印offsetX和offsetY

<div class="block" draggable="true"></div>
<script>
const box=document.querySelector('.block')
box.addEventListener('drag',function(e){
    console.log(e.offsetX,e.offsetY);
})
</script>

不断拖动的时候控制台一直在打印,很多时候这些打印对我们来说太频繁了,为了限制打印的频率。就可以对此进行节流 3.gif

节流的实现

定义一个throttle函数来做节流,将监听函数里的function作为throttle函数的参数,并且返回一个function,就相当于每次拖拽时执行的都是throttle函数

function throttle(fn){
  return function(){

  }
}  
box.addEventListener('drag',throttle(function(e){
  console.log(e.offsetX,e.offsetY);
}))

之后需要设置一个定时器,在返回的function外面定义一个timer变量为null,它只会初始化一次,在function里设置一个定时器,设置一个延时时间,时间到了执行传进来的方法

但是我们只希望执行一次,也就是连续触发事件但是在 n 秒中只执行一次函数,于是将定时器赋值给timer,然后判断如果已经有定时任务了将在未来执行传进来方法就直接return

并在计时结束的时候执行fn()并清空timer

function throttle(fn){
  let timer=null 
  return function(){
    if(timer) return 
    timer=setTimeout(() => {
      fn()
      timer=null
    }, 1000);
  }
}

可以看到节流也是实现了,只执行了一次fn()

3.gif

但是却出错了,无法读取未定义的属性(读取“offsetX”),只需将事件对象传给fn就行了,就可以正常打印offsetX和offsetY了

function throttle(fn){
  let timer=null 
  return function(event){
    if(timer) return 
    timer=setTimeout(() => {
      fn(event)
      timer=null
    }, 1000);
  }
}