防抖和节流

162 阅读2分钟

1. 前言

在实际的开发过程中,会遇到一些高频触发的事件,比如输入框的模糊匹配,输入框的搜索,轮播图的点击,回到顶部功能,改变窗口的resize等等,对于这些高频事件场景,可以使用防抖和节流减少事件触发次数。

2. 防抖

防抖:防止手抖(短时间内多次触发),忽略前面的触发,等手不抖了,只触发最后一次(也可以只触发第一次,忽略最后一次) 场景:输入框输入搜索 原理:如果两次触发的间隔时间小于我们定义的间隔时间(wait),忽略上一次触发,以下一次触发为准,即可以使用定时器延时执行触发,每次触发重置定时器

    <div id="app"></div>
    <button id='btn'>点击</button>
  </body>
  <script>
    var btn = document.getElementById('btn')
    function handler () {
      console.log('点击触发了')
    }
    btn.addEventListener('click', handler)
    
  </script>

此时每次点击按钮都会触发handler事件,此时我们可以自己封装一个防抖函数,去让事件延迟触发

    function handler () {
      console.log('点击触发了')
    }
    btn.addEventListener('click', debounce(handler, 300))
    function debounce (fn, wait) {
      // 参数容错处理
      if (typeof fn != 'function') throw new Error('first paramter must be a function')
      wait = wait || 300
      // 利用闭包定义一个计时器的初始值
      let timer = null
      // 每次点击实际触发的是handleClick函数
      return function handleClick (...args) {
        let self = this
        // 又一次触发handleClick时,如果定时器存在,需要清除定时器,重新开始计时
        if (timer) {
          clearTimeout(timer)
        }
        // 如果没有定时器,则定义一个定时器,如果后续没有再次触发handlerClick,传入的fn就会执行
        timer = setTimeout(() => {
          fn.apply(self, args)
        }, wait)
      }
    }

3. 节流

含义:顾名思义,开源节流,不是不执行,是减少频率的执行。可以理解为游戏里面的技能cd,在cd没有好的时候无论玩家怎么触发都不会执行。 场景:改变浏览器大小时触发的resize事件。 原理:事件触发后,指定的时间内不会再次触发事件,可以使用定时器,也可以使用时间差来处理。

    body {height: 5000px; }
  </style>
  <script>
    function scroll () {
      var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
      console.log('滚动位置:' + scrollTop)
    }
    window.onscroll = scroll

此时浏览器每次滚动都会多次触发scroll事件,可以使用节流减少触发次数

      var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
      console.log('滚动位置:' + scrollTop)
    }
    window.onscroll = throttle (scroll, 400)
    function throttle (fn, wait) {
      if (typeof fn != 'function') throw new Error ('must be a function')
      wait = wait || 300
      let cd = true
      // 滚动滚动条,实际上执行的是handleScroll函数
      return function handleScroll (...args) {
        let self = this
        // 如果技能cd没好,直接返回
        if (!cd)  return;
        cd = false
        setTimeout(() => {
          fn.apply(self, args)
          cd = true
        }, wait)
      }
    }