JavaScript函数防抖动debounce原理与应用详解

作者:巡夜人时间:2026-10-25 11:50:01浏览:433

本文详解JavaScript中防抖动(debounce)技术的原理与实现。通过一次性定时器延迟任务执行,并在再次触发时重置定时器,确保高频事件下仅执行最后一次操作。文章列举了滚动监听、表单输入、组件状态变更及窗口resize等典型应用场景,并提供完整代码示例与闭包实现方案,帮助开发者优化性能并提升用户体验。

防抖动简述

函数防抖动(debounce)旨在防止短时间内过于频繁地执行相同任务。当这种高频触发并非必要或可能影响体验时,采用防抖动机制可以有效避免资源浪费并提升用户交互的流畅度。

其核心原理是利用一次性定时器来延迟任务的执行。如果在设定的延迟时间内任务被再次触发,程序会通过 clearTimeout 销毁之前创建的定时器,从而取消前一次延迟执行的任务。这样便实现了在指定时间窗口内,无论触发多少次,最终只执行最后一次触发的任务。

防抖动与节流(throttle)在效果上相似,但实现逻辑存在差异。防抖动确保在短时间内连续多次触发时,仅执行最后一次操作,从而减少执行次数;而节流则是将多次执行转化为每隔固定时间执行一次,两者在控制频率的方式上略有不同。

防抖应用示例

1.防抖前后示例效果截图

防抖动简述

防抖动简述

2.防抖示例完整 demo

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>防抖动 Demo</title>
</head>
<body>
<h1>防抖动 Demo</h1>

<label>
    <span>输入昵称:</span>
    <input oninput="inputChange(event.data)"></input>
</label>

<script>

  let timer = null

  function inputChange (data) {
    // 不做防抖动会频繁触发校验,例如连续的输入两个字可能会触发6-7次,
    // 这种频繁程度可能不是必要的,当频繁不是必要的,那么就是资源的浪费。
    // validatePhone(data)

    // 防抖处理,连续正常的输入同样的两个字,只会触发一次校验任务。
    clearTimeout(timer)
    timer = setTimeout(() => {
      validatePhone(data)
    }, 1000)
  }

  function validatePhone (data) {
    let flag = true
    const regPhone = /^1\d{10}$/
    if (!regPhone.test(data)) {
      flag = false
      console.log('校验内容:' + data + '。手机号不正确,请输入1开头的11位手机号')
    }
    return flag
  }
</script>
</body>
</html>

防抖动的应用场景

当任务在短时间内被频繁执行,且这种高频并非业务必需时,即可考虑引入防抖动机制。以下列举了几个典型的应用场景:

①监听滚动条以实现左侧内容与右侧导航的联动。由于滚动条触发的频率极高,这种高频往往并非必要,此时使用防抖动处理是合适的选择。

例如在“JavaScript实现内容滚动与导航标签互动关联方案”一文中,便采用了防抖动技术来优化滚动监听逻辑。

// 监听滚动条
window.addEventListener("scroll", function (e) {
  // 防抖动处理
  clearTimeout(that.timeout)
  this.timeout = setTimeout(() => {
    that.activeNavNode(e)
  }, 100)
});

②表单输入相关的监听事件,例如 oninput 事件。

③部分组件库的内容变化监听,例如 el-tree 的 @check-change 事件。当选中父级选项时,由于会自动包含其子级选项,该事件会被频繁触发。若此变化关联接口调用,这种高频触发往往是不必要的。

下面是一个示例:

    <el-tree
      ref="tree"
      :data="treeData"
      show-checkbox
      @check-change="handleCheckChange">
    </el-tree>
handleCheckChange (data, checked, indeterminate) {
  // 简单的防抖动处理
  clearTimeout(this.timeout)
  this.timeout = setTimeout(() => {
    let checkedKeys = this.$refs.tree.getCheckedKeys()
    // 处理相关业务,例如根据选中的条件,触发接口查询
    // this.$emit('checkChange', checkedKeys.join(';'))
  }, 300)
},

④监听浏览器窗口大小变化(window.onresize)。在 echarts 等图表库的应用中,默认情况下窗口大小改变不会自动响应式调整布局,因此需要通过监听窗口变化并重置图表尺寸。实践中发现,调整窗口大小会极高频地触发 onresize 事件;若随之多次调用 echarts.resize(),不仅多余,还会导致界面闪烁、卡顿及性能浪费,此时适合使用防抖动处理。

下面是一个示例:

// 设备视口大小改变时,重置 echarts
let timer = null
window.onresize = function () {
  // 简单的防抖动处理
  clearTimeout(timer)
  timer = setTimeout(() => {
    console.log(timer)
    chart.resize()
  }, 500)
}

此外,也可以考虑使用闭包方式来实现,无需在外部声明 timer 变量,例如如下写法:

// 也可以考虑用闭包的方式
window.onresize = this.debounce(() => {
  chart.resize()
}, 500)

function debounce (fn, delay = 1000) {
  let timer = null
  return () => {
    if (timer) clearTimeout(timer)
    timer = setTimeout(fn, delay)
  }
}

⑤鼠标事件监听,例如拖拽操作。出于对准确性和及时性的要求,这类事件的响应非常细密;若业务层面不需要如此高频的处理,同样可以考虑使用防抖动技术。

到此这篇关于JavaScript函数防抖动debounce的文章就介绍到这了,更多相关JS防抖动内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

作者最新文章