节流防抖
防抖 (debounce) 与节流 (throttle ) 在实际中会经常使用。这两天仔细看了一下,有点理解了。
防抖 Debounce
含义: 在规定的时间内, 一个事件不管触发多少次, 最终只会执行一次, 在这个时间内, 如果再次被触发, 则会重新计时。即每次触发事件有一个 delay,在这个 delay 时间内,不会再次触发事件,只有 delay 时间后,才会触发事件。 好记一点: 防抖就是防止手抖。比如一个输入框,本意来说输入框的 value 会根据实时输入变化,但是呢,有些人手有问题,在不停地抖抖抖,所以输入框的值就会变化得很快。如果这是一个搜索框,需要实时返回搜索数据,那么请求就会发送很多很多,会对资源造成浪费。
实现
举例说明:
<style>
  .conatainer {
    width: 100%;
    height: 200px;
    text-align: center;
    line-height: 200px;
    color: #fff;
    background: #444444;
    font-size: 30px;
  }
</style>
<div class="container"></div>
<script>
  const conainer = document.querySelector('.container')
  let count = 1
  function getAction(e) {
    conainer.innerHTML = count + 1
  }
</script>
不防抖
container.onmousemove=getAction
这样的话当我们移动鼠标,container 中的数字会不断变化,也就是说getAction 会触发很多次。
实现防抖
function debounce(fn, delay) {
  let timer
  return function () {
    console.log(this)
    clearTimeout(timer)
    timer = setTimeout(fn, delay)
  }
}
container.onmousemove = debounce(getAction, 1000)
现在移动鼠标到停止移动, getAction只会在停止后 1s 触发一次。如果要触发第二次只有再次移动鼠标然后停止等 1s。
防抖中的 this
现在防抖已经是成功了,但是还有一个问题:上面的console.log(this)按照我们的意愿应该打印 container对象,但是上面打印出了 window。所以还需要进行一下修改:
function debounce(fn, delay) {
  let timer
  return function () {
    let that = this
    clearTimeout(timer)
    timer = setTimeout(function () {
      console.log(that)
      fn.apply(that)
    }, delay)
  }
}
container.onmousemove = debounce(getAction, 1000)
上面的代码暂存了一个this, 然后传入fn 的apply 方法, 这样在调用时this 的指向就会变成container 对象。
关于
apply请参阅Function.prototype.apply()
防抖函数的参数(event 对象)
js 在处理事件时, 会传入 evnet 对象;如果使用debounce函数,会打印 undefined:
function getAction(e) {
  console.log(e)
  conainer.innerHTML = count + 1
}
container.onmousemove = getAction //打印 event 对象
container.onmousemove = debounce(getAcion, 1000) // 打印undefined
所以,要对防抖函数进行修改,可以传入参数:
function debounce(fn, delay) {
  let timer
  return function () {
    let that = this
    let args = arguments
    clearTimeout(timer)
    timer = setTimeout(function () {
      fn.apply(that, args)
    }, delay)
  }
}
arguments是函数参数的类数组对象,详情请参阅Arguments 对象
节流 Throttle
含义: 在一个时间段内, 一个事件只会触发一次,如果在这个时间段内,事件被触发多次,只有第一次会执行,其余的会被忽略。
实现
举例说明:
<style>
  .conatainer {
    width: 100%;
    height: 200px;
    text-align: center;
    line-height: 200px;
    color: #fff;
    background: #444444;
    font-size: 30px;
  }
</style>
<div class="container"></div>
<script>
  const conainer = document.querySelector('.container')
  let count = 1
  function getAction(e) {
    conainer.innerHTML = count + 1
  }
</script>
不节流
container.onmousemove = getAction
同上,当我们移动鼠标,container 中的数字会不断变化,也就是说getAction 会触发很多次。
实现节流
function throttle(fn, delay) {
  let timer
  return function () {
    let that = this
    let args = arguments
    if (timer) {
      return
    }
    timer = setTimeout(function () {
      fn.apply(that, args)
      timer = null
    }, delay)
  }
}
container.onmousemove = throttle(getAction, 1000)
当我们一直移动鼠标,container 中的数字会一直变化,但是变化的频率是固定的,1s,也就是说getAction 会触发很多次,但是只有每隔 1s 才会执行一次。