防抖和节流的简单实现

67 阅读2分钟

前言

我们都知道,优化性能,提高用户体验一直都是前端要解决的问题,而 防抖节流 则是最简单的方法,那我们就开始吧

QQ图片20200201185557.jpg

概念和例子

防抖

指在一定时间内,多次触发同一个事件,只执行最后一次操作。也就是,比如说,某个事件是点击某个按钮的某段时间后触发的,而在这段时间内如果又点击的这个按钮,那么,时间则会重新计算,一直到这段时间耗尽。

我们来看一个 防抖 的例子(React):

export default function App() {
  // 事件
  const ajax = (content) => {
    console.log(`正在发起${content}的请求`)
    return null
  }
  // 防抖
  const debounce = (fun, delay) => {
    let timeout
    return function() {
      clearTimeout(timeout)
      timeout = setTimeout(() => {
        fun.apply(this, arguments)
      }, delay)
    }
  }
  
  const debunceAjax = debounce(ajax, 1000)
  
  return (
    <main>
      <div>
        防抖:<input onChange={e => debunceAjax(e.target.value)} />
      </div>
    </main>
  )
}


当我们在input输入框不断输入时,他并不会一直打印console,而是当我们在停下输入的1秒后才会有输出,这就是 防抖

比如说,当我们需要在页面大小改变时重新布局我们的页面,页面大小改变时window会触发resize,不断的调整浏览器窗口大小会不断的触发这个事件,这时候便能用到 防抖, 我们可以在页面大小保持不变的某段时间才开始重新布局,这样便舍去了中间从a宽到b宽的布局,当然能用到 防抖 的场景还有很多。

节流

在一定时间内,多次触发同一个事件,只执行第一次操作。

我们来看一个 节流 的例子(React):

export default function App() {
  // 事件
  const ajax = (content) => {
    console.log(`正在发起${content}的请求`)
    return null
  }
  // 节流
  function throttle2(fn, delay) {
    let canRun = true
    return function() {
      if (!canRun) return
      canRun = false
      setTimeout(() => {
        fn.apply(this, arguments)
        canRun = true
      }, delay)
    }
  }
  
  const throttleAjax = throttle2(ajax, 1000)
  
  return (
    <main>
      <div>
        节流:<input onChange={e => throttleAjax2(e.target.value)} />
      </div>
    </main>
  )
}

当我们在input输入框不断输入时,它只会每隔1秒打印一次console,不管中途输入几次,在这段时间内,只会触发一次事件,这就是 节流

比如说,当我们需要点击一个按钮去获取某些数据也就是从后端请求数据时,如果不断点击这个按钮则会不断发起请求,这是我们不需要的请求,这时候便可以用 节流 来保证在相应时间内点击只会触发一次,当然 节流 的应用场景也很多

总结

可以自己运行一下,看看它们的区别

export default function App() {
// 事件或者某个请求
  const ajax = (content) => {
    console.log(`正在发起${content}的请求`)
    return null
  }
  // 防抖
  const debounce = (fun, delay) => {
    let timeout
    return function() {
      clearTimeout(timeout)
      timeout = setTimeout(() => {
        fun.apply(this, arguments)
      }, delay)
    }
  }
  // 节流
  const throttle = (fun, delay) => {
    let last, deferTimer
    return function() {
      let now = +new Date()
      if (last && now < last + delay) {
        clearTimeout(deferTimer)
        deferTimer = setTimeout(() => {
          last = now
          fun.apply(this, arguments)
        }, delay)
      } else {
        last = now
        fun.apply(this, arguments)
      }
    }
  }

  //节流的第二种实现方法
  function throttle2(fn, delay) {
    let canRun = true
    return function() {
      if (!canRun) return
      canRun = false
      setTimeout(() => {
        fn.apply(this, arguments)
        canRun = true
      }, delay)
    }
  }
  // const throttleAjax = throttle(ajax, 1000)
  const throttleAjax2 = throttle2(ajax, 1000)
  const debunceAjax = debounce(ajax, 1000)
  
  return (
    <main>
      <div>
        防抖:<input onChange={e => debunceAjax(e.target.value)} />
      </div>
      <div>
        节流:<input onChange={e => throttleAjax2(e.target.value)} />
      </div>
    </main>
  )
}