节流函数(throttle)

节流:在频繁操作的时候,我们能降低触发的频率
节流函数原理:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。

<html>
  <input id="search" type="text" />
</html>
<script>
  const throttle = (fn, delay = 500) => {
    let flag = true
    return (...args) => {
      if (!flag) return
      flag = false
      setTimeout(() => {
        fn.apply(this, args)
        flag = true
      }, delay)
    }
  }

  /* 主要实现思路就是通过 setTimeout 定时器,通过设置延时时间。
  在第一次调用时,创建定时器,先设定一个变量true,写入需要执行的函数。
  第二次执行这个函数时,会判断变量是否true,是则返回。
  当第一次的定时器执行完函数最后会设定变量为false。
  那么下次判断变量时则为false,函数会依次运行。
  目的在于在一定的时间内,保证多次函数的请求只执行最后一次调用。 */

  const suggest = () => {
    console.log('fetch')
  }

  const debounceSuggest = throttle(suggest, 1000)

  let inputSearch = document.getElementById('search')
  inputSearch.addEventListener('input', () => {
    console.log('input')
    debounceSuggest()
  })
</script>

时间戳实现的方式

<script>
  // fn 是需要执行的函数
  // wait 是时间间隔
  const Throttle = (fn, wait = 50) => {
    // 上一次执行 fn 的时间
    let previous = 0
    // 将 Throttle 处理结果当作函数返回
    return function (...args) {
      // 获取当前时间,转换成时间戳,单位毫秒
      let now = +new Date()
      // 将当前时间和上一次执行函数的时间进行对比
      // 大于等待时间就把 previous 设置为当前时间并执行函数 fn
      if (now - previous > wait) {
        previous = now
        fn.apply(this, args)
      }
    }
  }

  // DEMO
  // 执行 Throttle 函数返回新函数
  const betterFn = Throttle(() => console.log('fn 函数执行了'), 1000)
  // 每 10 毫秒执行一次 betterFn 函数,但是只有时间差大于 1000 时才会执行 fn
  setInterval(betterFn, 10)
</script>
<script>
  const handle = function handle(ev) {
    console.log('ok')
  }
  
  /**
   * 函数节流处理
   *   @params
   *     func:最终要执行的函数[必传]
   *     wait:设定的触发频率[默认300MS]
   *
   * 默认:每间隔3MS左右,只要滚动条在滚动,我们就会把handle执行一次[触发频率是3MS]
   */
   const throttle = function throttle(func, wait) {
    if (typeof func !== 'function') throw new TypeError('func must be function')
    if (typeof wait !== 'number') wait = 300
    let timer,
      previous = 0
    return function proxy(...params) {
      let now = +new Date(),
        remaining = wait - (now - previous),
        self = this
      if (remaining <= 0) {
        // 间隔时间已经超过wait[包含第一次触发],无需等待,立即执行
        if (timer) {
          clearTimeout(timer)
          timer = null
        }
        func.call(self, ...params)
        previous = now
      } else if (!timer) {
        timer = setTimeout(() => {
          if (timer) {
            clearTimeout(timer)
            timer = null
          }
          func.call(self, ...params)
          previous = +new Date()
        }, remaining)
      }
    }
  }
  window.onscroll = throttle(handle, 300)
</script>

你可能感兴趣的:(JavaScript,javascript,前端)