JS中的防抖和节流

523 阅读3分钟

什么是防抖和节流

防抖

防止抖动,众所周知,在抖动的情况下容易发生高频触发。为了避免这种情况,防抖的核心是延迟执行,当间隔时间大于规定时间,才会触发执行方法。适用场景:实时搜索、拖拽。

节流

节省流量。是指若在规定的间隔时间内仍频繁重复操作,请求方法并不会重新发送,直到中间间隔时间大于规定的间隔时间,才会重新触发请求。适用场景:抢购疯狂点击。

为什么要防抖和节流

防抖和节流是为了防止频繁触发,消耗过多资源,甚至可能导致服务器崩溃的情况出现而提出的解决方案

它们的异同

相同点:

  1. 防抖和节流均是为了防止频繁触发、消耗过多资源而提出的解决方法。
  2. 防抖和节流的核心思想,均是设定一个规定的空隙时间,只有等待时间超过空隙时间才会请求数据。
  3. 防抖和节流的实现均要利用闭包,保护局部变量。

不同点:

  1. 防抖是延迟执行,等待时间超过规定时间才会执行。(一定时间后再执行)
  2. 节流是立即执行,中间等待时间超过规定时间才会再次执行。(先执行,一定时间内不再执行)

代码实现

防抖

事件被触发时,在n秒后执行函数,在n秒内多次触发事件,则重新开始计时

利用定时器来实现,在n秒内多次触发,则先清除定时器,重新计时

// 防抖-定时器实现
const debounce = (fn, ms = 0) => {
  let timeoutId
  return function(...args) {
    clearTimeout(timeoutId)
    timeoutId = setTimeout( () => fn.apply(this, args), ms)
  }
}
/*示例*/
// 定义一个请求函数
function request(val) {
    console.log(val)
}

// 定义一个防抖函数
function debounce(fn, delay) {
    let timeout
    return function() {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
            fn.apply(this, arguments)
        }, delay)
    }
}

let inputEl = document.getElementById('input')
let debounceInput = debounce(request, 500)
inputEl.addEvnetListener('keyup', function(e) {
    debounceInput(e.target.value)
})

只有当输入完成后才会触发函数,防止在不停是输入时调用函数,减少资源的浪费。

节流

在规定的单位时间段内,函数只能执行一次,在单位时间内多少触发,则只有一次有效

// 节流-定时器实现
const throttle = (fn, wait) => {
  let timer = null
  return function() {
    if (!timer) {
      timer = setTimeout(() => {
        timer = null
        fn.apply(this, arguments)
      }, wait)
    }
  }
}


// 节流-时间戳实现
const throttle = (fn, wait) => {
  let updateTime = Date.now()
  return (...args) => {
    const now = Date.now()
    if(now - updateTime > wait) {
      fn.apply(this, args)
      updateTime = now
    }
  }
}
/*示例*/
// 定义一个请求函数
function request(val) {
    console.log("request: " + val);
}

// 定义一个节流函数
function throttle(fn, delay) {
    let timer;
    return function(){
      if(!timer) {
        fn.apply(this, arguments)
        timer = setTimeout(()=>{
          clearTimeout(timer)
          timer = null
        },delay)
      }
    }
}

let inputEl = document.getElementById("input");

let throttleInput = throttle(request, 500)

inputEl.addEventListener("keyup", function (e) {
    throttleInput(e.target.value);
});

总结

  1. 防抖:防止抖动,单位时间内事件触发会被重置,避免事件被误伤触发多次。代码实现重在清零 clearTimeout

  2. 节流:控制流量,单位时间内事件只能触发一次,如果服务器端的限流即 Rate Limit。代码实现重在开锁关锁 timer=timeout; timer=null

  3. 防抖是将多次执行变为最后一次执行,节流是将多次执行变为每隔一段时间执行

  4. 防抖函数和节流函数都是用于控制函数调用频率,但是两者实现原理不同

  5. 防抖函数是在触发事件的单位时间后执行一次函数,在单位时间内多次触发不执行函数,重新计时

  6. 节流函数是单位时间内只执行一次函数,多次触发也只有一次有效

适用场景

  • 防抖

    1. 搜索输入框搜索内容,用户在不断的输入的时候,用防抖来节约请求资源
    2. 不断的触发window的resize事件,不断的改变窗口大小,利用防抖函数来只执行一次
  • 节流

    1. 鼠标不断的点击,用节流来限制只在规定的单位时间内执行一次函数
    2. 滚轮事件, 不断的往下滚轮,比如滚动到底部加载数据

参考链接

segmentfault.com/a/119000002…
segmentfault.com/a/119000002…
juejin.cn/post/696714…