JavaScript 防抖(Debounce)与节流(Throttle)详解与实现

叶初
叶初
发布时间:2026-10-16| 6人浏览过
原创

在 Web 开发中,频繁触发的事件(如滚动、输入、窗口缩放)若直接绑定回调函数,极易导致页面卡顿和资源浪费。防抖与节流是解决这一问题的两大核心技巧:防抖确保连续操作中只执行最后一次,适用于搜索联想等场景;节流则按固定频率执行,常用于鼠标移动或滚动加载。本文将解析其原理并展示基于定时器与时间戳的代码实现。

防抖(Debounce)

防抖的核心逻辑是“延迟执行”:当持续触发事件时,不执行回调,而是等待一段时间;若在等待期间再次触发,则重新计时。只有当事件停止触发的间隔超过设定时间后,回调函数才真正执行。

生活类比:想象按压弹簧。如果手指一直按住,弹簧处于压缩状态不会回弹;只有当手指松开(停止操作)并保持一段时间后,弹簧才会释放。这符合用户希望在完成所有输入动作后再进行搜索的场景。

第1步:非立即执行版防抖

这是最基础且最常用的写法。每次触发都会重置定时器,直到最后一次的触发点开始倒计时。该版本不支持首次立即执行。

function debounce(fn, wait) {
    var timer = null;
    return function () {
        // 清除上一次未执行的定时器
        if (timer !== null) {
            clearTimeout(timer);
        }
        // 设置新的定时器
        timer = setTimeout(() => {
            fn();
            // 注意:标准写法中通常使用 func.apply(this, arguments)
            // 此处为简化演示,假设无参数传递
        }, wait);
    }
}

// 使用示例:窗口大小改变时防抖
window.addEventListener("resize", debounce(function handle() {
    console.log('Resize triggered');
}, 1000));

第2步:常见生产环境写法

在生产环境中,需要正确处理 this 上下文和函数参数。以下写法更健壮:

const debounce = (func, delay = 200) => {
  let timeout = null;
  return function (...args) {
    // 保存 this 上下文
    const context = this;
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      // 恢复原始调用时的 this 和参数
      func.apply(context, args);
    }, delay);
  };
};

第3步:立即执行版防抖

在某些场景下(如点击按钮),我们需要第一次触发时就立即执行,后续连续触发则忽略,直到间隔结束。这种模式常用于防止重复提交。

function debounceImmediate(fn, wait) {
    let timer = null;
    let flag = true;
    
    return function (...args) {
        const context = this;
        
        // 如果有正在等待的定时器,先清除它,因为我们要重新开始计时
        if (timer !== null) {
            clearTimeout(timer);
        }
        
        // 如果是第一次或者上次调用已结束,则立即执行
        if (flag) {
            fn.apply(context, args);
            flag = false; // 标记为“忙碌”状态
            
            // 开始计时,计时结束后重置标志位,允许下一次立即执行
            timer = setTimeout(() => {
                flag = true;
            }, wait);
        } else {
            // 否则,启动一个计时器用于下次准备
             timer = setTimeout(() => {
                // 这里可以放置清理逻辑,但主要依赖 flag 控制
                // 实际上 immediate 模式下,中间触发都被忽略了,
                // 重点是下一个 wait 周期后的第一次触发能立即执行
                timer = null;
            }, wait);
        }
    };
}

总结防抖要点:适合搜索框输入建议、表单验证等“宁缺毋滥”且希望等待用户完成操作的场景。

节流(Throttle)

节流的核心逻辑是“固定频率”:无论事件触发多频繁,单位时间内只能执行一次。就像水龙头滴水,不管水流多大,规定时间内只能滴下一颗。

适用场景:窗口滚动加载、鼠标移动追踪、游戏循环刷新等需要平滑反馈但无需实时处理的场景。

第4步:基于时间戳的节流

通过记录上次执行的时间戳,判断当前时间与上次执行时间的差值是否大于阈值。这种方式首次触发会立即执行。

function throttleTimestamp(fn, wait) {
    let startTime = Date.now(); // 初始化起始时间
    
    return function (...args) {
        const context = this;
        let currentTime = Date.now();
        
        // 如果当前时间与上次执行时间间隔已超过 wait
        if (currentTime - startTime >= wait) {
            startTime = currentTime; // 更新起始时间为当前时间
            fn.apply(context, args); // 执行函数
        }
    };
}

注意:这种方式在执行周期结束时,可能会丢失最后一次触发,因为下一次触发被推迟到了下一个周期。

第5步:基于定时器的节流

利用 setTimeout 控制执行频率。如果在冷却期内再次触发,则丢弃该次触发。这种方式首尾的执行情况取决于具体逻辑(通常首次不立即执行,或者需结合时间戳)。这里展示标准的冷却期模式:

function throttleTimer(fn, wait) {
    let timer = null;
    
    return function (...args) {
        const context = this;
        
        // 如果定时器不存在,说明当前处于可用状态
        if (!timer) {
            timer = setTimeout(() => {
                fn.apply(context, args);
                timer = null; // 重置定时器状态,允许下次执行
            }, wait);
        }
    };
}

节流对比: 1. 时间戳方案:第一毫秒必执行,末尾可能少执行一次。 2. 定时器方案:第一毫秒不执行(除非特殊处理),末尾必执行一次。 综合来看,混合使用时间戳和定时器可以实现更精确的控制,但在大多数 UI 交互中,单独使用其中一种已足够优化性能。

总结

防抖和节流是前端性能优化的基石。简而言之:
- 遇到“连续操作,只需最后一次结果”(如搜索输入),使用防抖。
- 遇到“持续触发,需保持一定频率反馈”(如滚动加载),使用节流。
合理运用这两种模式,能显著降低浏览器渲染压力和服务器请求负载,提升用户体验。

以上就是 JavaScript 防抖与节流详解的详细内容,更多关于 JavaScript 性能优化的资料请关注本站其它相关文章!

相关标签:

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

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 算法库。