防抖和节流

175 阅读2分钟

防抖和节流都是防止函数过于频繁调用,但是又有所区别。防抖是短时间内只触发一次;节流是每隔一定的时间触发一次。

防抖

防抖是短时间内只触发一次,输入结束或者暂停的时候触发这个事件

应用场景

  1. 输入框发送变化的时候,监听onchange事件
  2. 监听键盘的keyup事件

自定义防抖函数

  1. 简单版本
  function debounce(func, wait) {
      let timeout
      return function () {
        let context = this
        let args = arguments
        clearTimeout(timeout)
        timeout = setTimeout(function () {
          func.apply(context, args)
        }, wait);
      }
    }
  1. 使用箭头函数
    function debounce(fn, wait) {
      let timeout
      return function (event) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          fn.call(this, event)
        }, wait);
      }
    }
  1. 增加一开始执行还是结束执行的选择
    //加上是否立即执行的判断
    function debounce3(func, wait, immediate) {
      let timeout
      return function () {
        let context = this
        let args = arguments
        clearTimeout(timeout)
        if (immediate) {
          let callNow = !timeout
          timeout = setTimeout(() => {
            timeout = null
          }, wait);
          if (callNow) func.apply(context, args)
        } else {
          timeout = setTimeout(function () {
            func.apply(context, args)
          }, wait);
        }
      }
    }

节流

如果持续触发事件,每隔一段时间只执行一次事件

应用场景

  1. scroll事件滚动触发
  2. 搜索框输入查询
  3. 表单验证
  4. 浏览器的的窗口缩放:resize事件

节流的两种方式

  1. 时间戳
    //使用时间戳,一开始进入就执行,结束之后不会再有一次执行
    function throttle(func, wait) {
      let old = 0;
      let args
      return function () {
        args = arguments
        let now = Date.now()
        if (now - old > wait) {
          func.apply(this, args)
          old = now
        }
      }
    }
  1. 定时器
    //使用定时器 第一次不会触发,最后一次会触发
    function throttle1(func, wait) {
      let args, timeout
      return function () {
        args = arguments
        if (!timeout) {
          timeout = setTimeout(() => {
            timeout = null
            func.apply(this, args)
          }, wait);
        }
      }
    }
  1. 时间戳和定时器结合
    //开始立即执行,结束之后过了wait的时间还会再执行一次
    function throttle2(func, wait) {
      let old = 0
      let args, timeout
      return function () {
        args = arguments
        let now = Data.now()
        //只负责在刚一进来执行一次
        if (now - old > wait) {
          if (timeout) {
            clearTimeout(timeout)
            timeout = null
          }
          fucn.apply(this, arguments)
          old = now
        }
        if (!timeout) {
          timeout = setTimeout(() => {
            old = Date.now()
            timeout = null
            func.apply(this, arguments)
          }, wait);
        }
      }
    }