防抖和节流

218 阅读2分钟

函数防抖(debounce)

在事件被触发n秒后再执行回调,如果再这n秒内又被触发,则重新计算

看一个例子:

没有防抖的input: <Input id="unDebounce">
防抖后的input <input>
节流后的input <input>
// 模拟一段ajax请求
function ajax(content) {
  console.log('ajax request' + content);
}
let inputa = document.getElementById('unDebounce')
inputa.addEventListener('keyup', function (e) {
  ajax(e.target.value)
})

看下运行效果: p1-jj.byteimg.com/tos-cn-i-t2… 可以看到,我们只要按下键盘,就会触发这次ajax请求,不仅仅从资源上来说是很浪费的行为,而且实际应用中,用户也是输出完整的字符后,才会请求,下面我们优化一下

// 防抖——触发高频事件后 n 秒后函数只会执行一次,如果 n 秒内高频事件再 次被触发,则重新计算时间;
  function debounce(fn) {
    let timeout = null
    // 创建一个标记用来存放定时器的返回值
    return function () {
      clearTimeout(timeout)
      // 每当用户输入的时候把前一个 setTimeout clear 掉
      timeout = setTimeout(() => {
        // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
        fn.apply(this, arguments)
      }, 500)
    }
  }

  function sayHi(n) {
    console.log('防抖成功')
  }

  var inp = document.getElementById('debounce')
  inp.addEventListener('input', debounce(sayHi)) // 防抖

函数节流(throttle)

规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效

 function throttle(fn) {
    let canRun = true
    // 通过闭包保存一个标记
    return function () {
      if (!canRun) return
      // 在函数开头判断标记是否为 true,不为 true 则 return
      canRun = false // 立即设置为 false
      setTimeout(() => {
        // 将外部传入的函数的执行放在 setTimeout 中
        fn.apply(this, arguments)
        // 最后在 setTimeout 执行完毕后再把标记设置为 true(关键) 表 示可以执行下一次循环了。当定时器没有执行的时候标记永远是 false,在开头被 return 掉
        canRun = true
      }, 10000)
    }
  }

  function sayHi(e) {
    console.log('节流!!!!~~~')
  }

  // window.addEventListener('resize', throttle(sayHi))
  document.getElementById('debounce').addEventListener('input', sayHi)