JavaScript防抖和节流

摘要

防抖和节流是开发过程中经常会遇到的业务问题,本文旨在剖析其实现逻辑,帮助更多开发者掌握并运用此项开发技巧,提高业务水平

  • 防抖:无论事件处理函数触发多少次,其中的每一次执行都将延迟 N秒执行

  • 节流:事件处理函数无论触发多少次在N秒内只执行一次


防抖函数具体实现

根据防抖函数的定义,首先我们需要一个提供事件处理的函数,这里用 fn举例

const button = document.getElementsByTagName('button').item(0);
button.addEventListener('click', fn);    // 使用 click 事件模拟更加直观
function fn() {
    console.log(new Date().getSeconds());    // 这里 fn 每次执行时会输出当前秒数,用于展示延迟时间
}

由于事件处理需要一个函数,且我们需要对已有的函数进行改造,但为了尽量不修改原函数。因此可以想到使用函数闭包来解决这个问题

function debounce(event, wait) {
    return function (...args) {    // 当存在后续参数时给予接收
    };
}

然后,因为需要延迟执行,所以可以使用定时器实现,且因不需要循环执行,则选择采用 setTimeout

function debounce(event, wait) {    // 接收处理函数和定义的延迟时间
    return function (...args) {    // 当存在后续参数时给予接收
        timer = setTimeout(() => {
            event.apply(this, args);    // 采用 apply 是因为 args 的类型为数组
      }, wait);
    };
}

此时,一个粗糙的防抖函数就实现了,但此时,其功能还不稳定。由于每一次触发完毕都会设定一个定时器,因此需要对其进行清除,以免干扰下一次延迟

function debounce(event, wait) {    // 接收处理函数和定义的延迟时间
    let timer = null;    // 由于后续需要清除定时器,因此需先声明变量作为定时器的标识
    return function (...args) {    // 当存在后续参数时给予接收
        if (timer) clearTimeout(timer);   // 触发后清除上一次创建的定时器
        // 延时执行给定的处理函数 
        timer = setTimeout(() => {
            event.apply(this, args);    // 采用 apply 是因为 args 的类型为数组
      }, wait);
    };
}

到此,一个功能正常的防抖函数就实现了。此时每一次触发都需延迟 wait 毫秒,而实际业务中首次触发并不需要延时,否则用户往往会感到莫名其妙。因此,我们选择加入第三个参数 immediate

function debounce(event, wait, immediate) {
    let timer = null;
    return function (...args) {
        clearTimeout(timer);
        if (!timer && immediate) event.apply(this, args);  // 若计时器为空且立即参数为真即执行函数
        // 若不满足条件则按正常计划使用定时器延迟执行
        else {
            timer = setTimeout(() => {
                event.apply(this, args);
            }, wait);
        }
    }
}

至此,一个正常的具有使用价值的防抖函数就完成了。其使用场景在于需要延迟执行请求或操作的情况下,如窗口变化或表单延迟校验等


节流函数具体实现

根据节流函数的定义,当处理函数多次触发时,只在规定时间内执行一次。这里提供了两种思路:时间戳和定时器

  • 时间戳的原理是当第一次执行前保存触发时间,后续触发时判断是否大于或等于必须等待的时间,从而达到限制执行次数的目的

  • 定时器则和防抖函数延时处理的逻辑差不太多,当重复触发时清除定时器,并执行最后一次触发的定时器,以达到限制执行次数的目的

时间戳方式

此种方式的缺点是最后一次触发事件时不会执行。经查阅网络资料,发现大多是把保存上次触发时间的变量放进了函数内,导致每次执行函数时old变量都会被重置,以致丢失保存的时间,无法实现节流效果。当然,也有可能是我未发现其中深意,如有懂其设计思路的朋友,欢迎在评论区留言,在此感谢

let old = 0;   // 设定全局变量用于保存上一次触发的时间
function throttle(event, wait) {
    return function (...args) {
        if (new Date() - old >= wait) {
            fn.apply(this, args);
            old = new Date();    // 记录当前触发的时间
        }
    }
}

定时器方式

此种方式的缺点是第一次触发事件时不会执行,也曾参详过知乎和CSDN上的博客,发现同样是把timer变量放入了函数内部导致调用时被重置。当然,如有更好的实现方式,欢迎留言指正,感谢

let timer = null;
function throttle(event, wait) {
    return function (...args) {
        clearTimeout(timer);
        timer = setTimeout(() => {
            event.apply(this, args);
        }, wait)
    };

因为两种方式本身都有缺陷,为解决这种缺陷,可以把两者结合起来使用

let old = 0, timer = null;
function throttle(event, wait) {
    return function (...args) {
        if (new Date() - old >= wait) {
            fn.apply(this, args);
            old = new Date();
        } else {
            clearTimeout(timer);
            timer = setTimeout(() => {
            event.apply(this, args);
        }, wait)
        }
    }
}

总结

防抖函数和节流函数本身原理并不复杂,但难在如何设计一个功能完备且健壮性高的函数

在本文中,我也有许多不解之处,经过多方查看,最终勉强算是解决了这个问题。由此,坚持就是胜利这句话还是有可取之处的,在后续的技术分享博客中,我将贯彻这一精神,望各位能够支持,感谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript中的防抖节流是为了控制函数的执行频率,以提高性能和优化用户体验。 防抖(debounce)是指在一定的时间间隔内,只执行最后一次操作。引用提供了一个自定义的防抖函数示例。该函数接受两个参数:待执行的函数和延迟时间。在函数调用时,如果在延迟时间内再次触发了函数调用,则会清除之前的定时器,重新设置一个新的定时器,以延迟函数的执行。 节流(throttle)是指在一定的时间间隔内,限制函数的执行频率。引用和提供了两个不同的节流函数示例。这些节流函数都可以指定一个时间间隔,只有在这个时间间隔内函数没有被执行过才能继续执行。其中,引用实现了一个基于定时器的节流函数,而引用则是一个基础版的节流函数,使用了时间戳来判断是否达到执行条件。 需要注意的是,防抖节流可以根据具体的需求和场景来选择使用,以达到更好的效果。防抖适用于需要等待用户停止操作后才执行的场景,而节流适用于需要限制函数执行频率的场景。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [JavaScript 防抖节流的实现](https://blog.csdn.net/weixin_43853746/article/details/122654312)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [【JavaScript防抖(debounce)、节流(throttling)](https://blog.csdn.net/qq_46658751/article/details/123386755)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值