Skip to content

关于 js 的防抖和节流

看例子:

当鼠标在橙色区域来回移动时 已经被绑定了移入事件的div 可以看到数值在不可控的快速增加,说明该函数被频繁触发。 对于这种快速连续触发和不可控的高频率触发问题,我们有 防抖(debounce)节流(throttle) 这两种解决方法。

防抖(debounce)

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

防抖函数分为非立即执行版和立即执行版。

javascript
//准备工作
let num = 1 //定义一个初始值
let content = document.getElementById('content') //先获取一下

function count() {
  //自增函数
  content.innerHTML = num++
}

非立即执行版:短时间内多次触发函数,只会执行最后一次,中间的不执行

javascript
//非立即执行版
function debounce(func, wait) {
  let timer
  return function () {
    let context = this // 注意 this 指向
    let args = arguments // arguments中存着e

    if (timer) clearTimeout(timer)

    timer = setTimeout(() => {
      func.apply(this, args)
    }, wait)
  }
}

//使用方法
content.onmousemove = debounce(count, 1000)

立即执行版:短时间内多次触发函数,只会执行第一次,中间的不执行

javascript
//立即执行版
function debounce(func, wait) {
  let timer
  return function () {
    let context = this
    let args = arguments // arguments中存着e

    if (timer) clearTimeout(timer)

    let callNow = !timer

    timer = setTimeout(() => {
      timer = null
    }, wait)

    if (callNow) func.apply(context, args)
  }
}

//使用方法
content.onmousemove = debounce(count, 1000)

节流(throttle)

所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。 用一句话总结防抖和节流的区别:防抖是将多次执行变为最后一次执行,节流是将多次执行变为每隔一段时间执行 节流函数主要有两种实现方法:时间戳和定时器。

时间戳版:获取上一次触发的时间再减去当前触发的时间,如果大于指定时间就会被执行,否则就不会执行

javascript
// 时间戳版
function throttle(func, wait) {
  let previous = 0
  return function () {
    let now = Date.now()
    let context = this
    let args = arguments
    if (now - previous > wait) {
      func.apply(context, args)
      previous = now
    }
  }
}

//使用方法
content.onmousemove = throttle(count, 1000)

定时器版:如果一直不断地触发函数,它会按照指定的时间执行函数

javascript
//定时器版
function throttle(func, wait) {
  let timeout
  return function () {
    let context = this
    let args = arguments
    if (!timeout) {
      timeout = setTimeout(() => {
        timeout = null
        func.apply(context, args)
      }, wait)
    }
  }
}

//使用方法
content.onmousemove = throttle(count, 1000)

如有错误请指正