防抖(debounce)指的是:事件连续不断触发,只响应最后一次。
实际的运用场景是:滚动、鼠标高频点击、窗口大小连续变化、input输入等事件,会频繁触发响应函数,但我们不需要这么频繁的响应。我们觉得这一波高频事件完成后再做一次响应就行了。
因此防抖的具体过程是:事件触发后设置“沉默”定时器,并清除之前的定时器,“沉默”一定时间(不会太长)后,定时器到期并执行动作。

这篇文章的时间线图片可以帮助理解:js防抖和节流

先不考虑封装函数。针对scoll的防抖应该是这样:

<script>
    document.addEventListener('DOMContentLoaded', function () {
        var timer = null;
        document.addEventListener('scroll', function () {
            // console.log('scolling');
            clearTimeout(timer);
            timer = setTimeout(function () {
                console.log('scrolled DEBOUNCE');
            }, 1000);
        });
    });
</script>

页面加上大段文字或者<br>就能看出滚动防抖的效果了。(如果你的浏览器不支持监听document的scoll,试试改成window或document.body)
代码中输出“scrolling”那行被注释掉了,如果没注释,就会不断地输出“scrolling”;相比之下,防抖的输出“scrolled DEBOUNCE”只会在滚动停止1000ms后输出一次。

接下来是封装函数。一开始我想到的封装是这样子的:

<script>
    document.addEventListener('DOMContentLoaded', function () {
        function debounce(dom, eventType, wait, handler) {
            var timer = null;
            dom.addEventListener(eventType, function () {
                clearTimeout(timer);
                timer = setTimeout(function () {
                    handler();
                }, wait);
            });
        }

        debounce(document, 'scroll', 1000, function () {
            console.log('you stopped scrolling 1000ms ago');
        });
    });
</script>

形式太low了。看了别人的封装形式,针对响应动作封装就好。参数就是关于做什么动作、延迟多久才做,尽量不改变原有的监听语句形式。改成这样:

<script>
    document.addEventListener('DOMContentLoaded', function () {
        function debounce(handler, delay) {
            var timer = null;
            return function () {
                clearTimeout(timer);
                timer = setTimeout(function () {
                    handler();
                }, delay);
            }
        }

        document.addEventListener('scroll', debounce(function () {
            console.log('you stopped scrolling 1000ms ago');
        }, 500));
    });
</script>

完成。防抖我觉得还是比较好理解的,下一篇说节流更绕一点。


BENCJL
15 声望0 粉丝

问天问大地