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

本文共 3060 字,大约阅读时间需要 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库的实现进行深入理解。


    参考

    你可能感兴趣的文章
    RabbitMQ - 消息堆积问题的最佳解决方案?惰性队列
    查看>>
    php怎样比较两数大小,jquery如何判断两个数值的大小
    查看>>
    PHP性能监控 - 开启xhprof(一)
    查看>>
    PHP性能监控 - 怎么看xhprof报告(二)
    查看>>
    php截取字符串代码,PHP字符串截取_php
    查看>>
    php截取字符串,无乱码
    查看>>
    php手冊,php手冊之變量范圍
    查看>>
    PHP手机号码归属地查询API接口
    查看>>
    PHP执行耗时脚本实时输出内容
    查看>>
    PHP扩展安装
    查看>>
    php把get参数放入数组_php怎么将数组转为url参数?
    查看>>
    php操作mysql用select_php如何操作mysql获取select 结果
    查看>>
    PHP操作符与控制结构
    查看>>
    PHP支付宝SDK使用,电脑网页支付
    查看>>
    php支付宝手机网页支付类实例
    查看>>
    php教程之php空白页的原因及解决方法
    查看>>
    PHP数据库操作
    查看>>
    PHP数据文件过大,导致PHP加速器eaccelerator在PHP5.2版本下崩溃
    查看>>
    RabbitMQ - 死信、TTL原理、延迟队列安装和配置
    查看>>
    PHP数据访问的多重查询(租房子查询)
    查看>>