博客
关于我
JS魔法堂:函数节流(throttle)与函数去抖(debounce)
阅读量:429 次
发布时间:2019-03-06

本文共 3135 字,大约阅读时间需要 10 分钟。

debounce与throttle:JavaScript事件防抖动的两种解决方案


前言

在实际开发中,频繁触发DOM操作或资源加载可能导致UI卡顿甚至浏览器崩溃。以下场景经常引发问题:

  • window对象的resize、scroll事件
  • 拖拽时的mousemove事件
  • 射击游戏中的mousedown、keydown事件
  • 文字输入、自动完成的keyup事件
  • 针对这些事件,有两种常见的解决方案:debouncethrottle


    debounce:防抖动机制的定义

    debounce 的核心思想是:在指定的空闲时间内,多次触发同一事件只执行一次。类似于弹簧的状态,只有在手松开后才会恢复原状。

    简单实现:

    var debounce = function(idle, action) {
    var last = null;
    return function() {
    var ctx = this;
    var args = arguments;
    clearTimeout(last);
    last = setTimeout(function() {
    action.apply(ctx, args);
    }, idle);
    };
    };

    throttle:速率限制机制的定义

    throttle 的目标是限制事件处理的执行频率。每隔指定时间执行一次相关操作,类似于水流的滴落。

    简单实现:

    var throttle = function(delay, action) {
    var last = 0;
    return function() {
    var curr = +new Date();
    if (curr - last > delay) {
    action.apply(this, arguments);
    last = curr;
    }
    };
    };

    Underscore v1.7.0的实现剖析

    _.throttle函数

    _.throttle = function(func, wait, options) {
    var context, args, result;
    var timeout = null;
    var previous = 0;
    if (!options) options = {};
    var later = function() {
    previous = options.leading === false ? 0 : _.now();
    timeout = null;
    result = func.apply(context, args);
    if (!timeout) context = args = null;
    };
    return function() {
    var now = _.now();
    if (!previous && options.leading === false) previous = now;
    var remaining = wait - (now - previous);
    context = this;
    args = arguments;
    if (remaining <= 0 || remaining > wait) {
    if (timeout) {
    clearTimeout(timeout);
    timeout = null;
    }
    previous = now;
    result = func.apply(context, args);
    if (!timeout) context = args = null;
    } else if (!timeout && options.trailing !== false) {
    timeout = setTimeout(later, remaining);
    }
    return result;
    };
    };

    精彩之处

    • remaining <= 0 用于检测是否满足空闲时间。
    • remaining > wait 用于处理时间异常(如系统时间修改)。

    _.debounce函数

    _.debounce = function(func, wait, immediate) {
    var timeout, args, context, timestamp, result;
    var later = function() {
    var last = _.now() - timestamp;
    if (last < wait && last > 0) {
    timeout = setTimeout(later, wait - last);
    } else {
    timeout = null;
    if (!immediate) {
    result = func.apply(context, args);
    if (!timeout) context = args = null;
    }
    }
    };
    return function() {
    context = this;
    args = arguments;
    timestamp = _.now();
    var callNow = immediate && !timeout;
    if (!timeout) timeout = setTimeout(later, wait);
    if (callNow) {
    result = func.apply(context, args);
    context = args = null;
    }
    return result;
    };
    };

    精彩之处

    • 递归调用 setTimeout 来确保在空闲时间内只执行一次函数。
    • immediate 参数控制是否在首次调用时立即执行函数。

    总结

    debouncethrottle 都通过减少事件处理的执行频率来提升性能,但核心机制有明显差异:

    • debounce 更关注空闲时间,适用于需要延迟处理的场景。
    • throttle 则强调执行频率,适用于需要稳定化处理的场景。

    选择时需结合具体需求,结合各JS库的实现进行深入理解。


    参考

    你可能感兴趣的文章
    NumPy中的精度:比较数字时的问题
    查看>>
    numpy判断对应位置是否相等,all、any的使用
    查看>>
    Numpy多项式.Polynomial.fit()给出的系数与多项式.Polyfit()不同
    查看>>
    Numpy如何使用np.umprod重写range函数中i的python
    查看>>
    numpy学习笔记3-array切片
    查看>>
    numpy数组替换其中的值(如1替换为255)
    查看>>
    numpy数组索引-ChatGPT4o作答
    查看>>
    numpy最大值和最大值索引
    查看>>
    NUMPY矢量化np.prod不能构造具有超过32个操作数的ufunc
    查看>>
    Numpy矩阵与通用函数
    查看>>
    numpy绘制热力图
    查看>>
    numpy转PIL 报错TypeError: Cannot handle this data type
    查看>>
    Numpy闯关100题,我闯了95关,你呢?
    查看>>
    nump模块
    查看>>
    Nutch + solr 这个配合不错哦
    查看>>
    NuttX 构建系统
    查看>>
    NutUI:京东风格的轻量级 Vue 组件库
    查看>>
    NutzCodeInsight 2.0.7 发布,为 nutz-sqltpl 提供友好的 ide 支持
    查看>>
    NutzWk 5.1.5 发布,Java 微服务分布式开发框架
    查看>>
    NUUO网络视频录像机 css_parser.php 任意文件读取漏洞复现
    查看>>