JavaScript函数防抖(Debounce)原理与应用实战

码头散步
码头散步
发布时间:2026-10-15| 2人浏览过
原创

JavaScript函数防抖(Debounce)旨在解决短时间内频繁触发事件导致的性能问题。其核心逻辑是利用定时器延迟任务执行,若期间再次触发则重置计时器,从而确保仅在静止状态后执行一次操作。

防抖动简述

函数防抖动(debounce):防止在短时间内过于频繁地执行相同的任务。当短时间内的频繁触发是不必要的时候,就可以考虑去抖动,避免资源浪费或造成不好的用户体验。

函数防抖动的原理,主要是利用一次性定时器,延迟任务的执行。在延迟这段时间内,如果任务再次被触发,则通过 clearTimeout 销毁上一次产生的定时器。因为定时器的被销毁,之前被延迟执行的任务也会随之被取消执行。这样就实现了在一定时间内,只执行一次任务。这一次的执行通常是最后一次的触发,因为此前的触发因为定时器的销毁而被取消了。

多次触发只执行最后一次或许就是和“节流”概念的区别?它们两在作用上挺像的,在具体实现上略有不同。函数防抖(debounce)是短时间内连续多次触发,但只执行最后一次,即是说将多次执行变成了只执行最后一次,执行次数减少。而节流(throttle)是将短时间的多次执行,变成每隔一段时间执行一次。

防抖应用示例

第1步:查看防抖前后效果对比

第2步:构建防抖完整Demo

以下是一个基于 input 事件的防抖示例,演示如何对表单输入进行实时校验而不产生过多计算开销。

<!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>

防抖动的应用场景

当任务在短时间内被频繁执行,而这种频繁不是必要的,或不是想要的,就可以考虑使用防抖。下面是一些场景例子:

1. 监听滚动条联动导航

①监听滚动条实现左侧内容和右侧导航关联,滚动条的频繁程度很高,而这种频繁程度可能不是我们想要的,此时就可以考虑使用防抖。

例如我在 JavaScript实现内容滚动与导航标签互动关联方案中就使用了防抖。

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

2. 表单输入监听

②表单输入的一些监听事件,例如 oninput 等。

3. 组件库内容变化监听

③一些组件库的内容变化监听,例如 el-tree 的 @check-change 事件,当选择祖先级的选项时,因为包含了选中其子孙项,@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)
},

4. 监听浏览器窗口大小变化

④监听浏览器窗口变化 window.onresize,例如在 echarts 的应用中,默认浏览器窗口大小改变 echarts 视图布局是不会做响应式改变的,那么就需要通过监听浏览器窗口大小改变然后去重置 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)
  }
}

5. 鼠标拖拽事件监听

⑤鼠标事件,例如拖拽等的监听等,出于准确性和及时性,它们的监听响应十分细密,而当这种频繁在业务上可能不是必要的,那么也可以考虑使用防抖动技术。

以上就是JavaScript函数防抖动debounce的详细内容,更多关于JS防抖动优化的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。