防抖和节流

108 阅读2分钟

debounce

触发事件后的一段时间内不再触发,事件会被执行,如果在这段时间内触发,那么需要重新计时

使用场景

  • 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时使用防抖,比如在2s内,不断调整窗口大小,那么不执行resize,直到这2s内不调整了,就可以执行resize了
  • 文本编辑器实时保存,当无任何更改操作一秒后进行保存

代码实现

  1. 把触发的事件封装好,作为参数传入debounce
  2. 因为是一段时间内不触发,那么就执行,通过使用定时器完成
  3. 如果在这段时间内触发,就要重新计时,通过使用清除定时器实现
  // fn,触发事件
  // delay,一段时间内不触发事件
  // immediately,立即执行和非立即执行类型
  function debounce(fn, wait, immediate) {
    let timer;
    return function () {
      if (timer) clearTimeout(timer);
      if (immediate) {
        immediate = !immediate; // 取个反
        fn.apply(this, arguments);
        timer = setTimeout(() => {
          timer = null
        }, wait)
      } else{
        timer = setTimeout(() => {
          fn.apply(this, arguments);
        }, wait)
      }
      

    }
  }

节流throttle

触发事件后的一段时间内不再触发,事件会被执行,如果在这段时间内触发,那么会被无视

使用场景

  • 滚动加载,加载更多或滚到底部监听,只要页面滚动就会间隔一段时间判断一次
  • 搜索框,搜索联想功能

代码实现

  1. 触发函数时,在规定时间内只执行一次, 也是用定时器完成
  2. 在规定时间内多次触发,会无视掉第一次之后的触发操作
  3. 因为在规定时间要执行,那么只能生成一个定时器,等规定时间过后,如果继续触发操作,才能生成一个新的定时器,需要一个节流阀来控制定时器的生成
    // fn,触发事件
    // delay,规定时间内
    // immediately,立即执行和非立即执行类型
    function throttle(fn, delay, immediate) {
      let timer = null
      return function () {
        const context = this
        const arg = arguments
        if (immediate) {
          fn.apply(context, arg)
          if(!timer) {
            timer = setTimeout(() => {
              // fn.apply(context, arg)
              timer = null
            }, delay);
          }
        } else{
          if(!timer) {
            timer = setTimeout(() => {
              fn.apply(context, arg)
            }, delay);
          }
        }
        
      }
    }