JavaScript编程之防抖和节流

更新 2023年03月18日 追加概述

在编程中防抖 (debounce) 和节流 (throttle) 都是为了解决某些事件频繁触发,导致性能受到影响的问题。不过它们的策略略有不同:

防抖

防抖的原理是在触发事件后,设立一个等待时间,如果在等待时间内再次触发事件,则重新计时,直到等待时间结束后才执行事件。类比于现实中的抖动开关,如果频繁地切换开关状态,只有最后一个状态确定后才能执行对应的操作。

举个例子,当用户连续快速点击按钮时,防抖能够确保只有最后一个点击事件被触发,而前几次点击事件会被忽略。

节流

节流的原理是在设定时间内,无论事件触发了多少次,只执行一次事件。类比于现实中的自来水龙头,打开后持续流水时,为了避免水资源的浪费,在很短的时间段内,每隔一段时间就会流出一次水滴。

再举一个例子,当用户滚动滚动条时,节流能够确保每隔一定时间才执行一次处理逻辑,避免了处理逻辑的频繁触发。

因此,防抖和节流的策略不同,根据实际的使用场景,我们可以选择合适的策略来减少频繁事件的触发,提高代码的执行效率。

一个经典的比喻:

想象每天上班大厦底下的电梯。把电梯完成一次运送,类比为一次函数的执行和响应

假设电梯有两种运行策略 debounce 和 throttle,超时设定为15秒,不考虑容量限制

电梯第一个人进来后,15秒后准时运送一次,这是节流

电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖


1.防抖 (debounce)

原理:

只以最后一次触发的时间为准,延迟n秒后才执行。如果延迟n秒的时间内又触发事件,则以新的事件为时间基准,延迟n秒再执行 应用场景:

登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖
调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖
文本编辑器实时保存,当无任何更改操作一秒后进行保存

简单代码:防抖重在清零 clearTimeout(timer)

function debounce(func, wait) {
    var timeout;

    return function () {
        clearTimeout(timeout)
        timeout = setTimeout(func, wait);
    }
}

// 不断的调用 debounce(some_action, 1000)
// 以最后一次调用为准进行延迟

2.节流 (throttle)

原理:

控制事件发生的频率,如控制为1s发生一次,甚至1分钟发生一次 应用场景:

scroll 事件,每隔一秒计算一次位置信息等
浏览器播放事件,每个一秒计算一次进度信息等
input 框实时搜索并发送请求展示下拉列表,每隔一秒发送一次请求 (也可做防抖)

简单代码:节流重在开锁关锁 timer = setTimeout timer = null、nowTime - lastTime > wait

//1.设置定时器
function throttle(func, wait) {
    var timeout = null;

    return function() {
        if (!timeout) {
            timeout = setTimeout(function(){
                timeout = null;
                func()
            }, wait)
        }
    }
}

//2.使用时间戳
function throttle2 (func, wait) {
    let lastTime = 0;

    return function () {
        let nowTime = +new Date();
        if (nowTime - lastTime > wait) {
            func();
            lastTime = nowTime
        }
    }
}

// 这里必须假象,在 某在场景比如 scroll中,这个函数被多次频繁调用
// 频繁调用的场景下思考这个函数才有意义
// 尤其是第二个时间辍方法,就是在频繁调用,他检查时间辍才有意义

参考

Mark24

Everything can Mix.