防抖和节流白话文版

135 阅读2分钟

这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战

目前在许多前端面试题中会要求手写防抖、节流,对于前端工程师来说已经是必备技能,如果你还不了解?纳尼!快把本文阅读一遍。

先从概念上认识它:防抖和节流

为什么要做防抖、节流

想象一下我们所开发的程序上线后,当用户在程序上执行特定操作(如按下按键、单击鼠标、调整窗口大小等)时,它可能会发出某种事件,但当用户重复执行特定操作时(比如继续按下按键、调整窗口大小等),程序会继续触发相同的事件并执行我们为处理这些事件所编写的函数。

把上面的文字翻译成代码,可能酱样子的 :

function resize() {
     console.log("窗口大小被改变");
}
window.addEventListener('resize', resize);

88.gif

上述代码中对 resize 事件进行监听,当可视区变化时,resize 事件被触发多次。显然多次触发是不必要的,如果在事件触发执行的函数中再去向服务器发送一些 HTTP 请求,无疑就造成了更大了资源浪费。

问:有什么好的解决方式嘛 ?

菜花🥥:不让用户操作 。 ( OS : 噗 下一个)

西蓝花🥦:用一种方式来过滤或尽可能最少次的去调用函数,以保持用户体验相同。

答:(o゜▽゜)o 对,这就是本文重点要介绍的防抖Debounce和节流Throttle。二者是两种非常相似的处理函数调用的性能优化方法。

什么是防抖、节流

防抖Debounce

防抖是指触发事件后,在规定时间内事件处理函数只会执行一次,如果在规定时间内触发了该事件,则会重新开始算规定时间。

节流Throttle

节流是指在规定时间内持续触发事件,只会执行一次事件处理函数。如果在指定时间内触发多次函数,只有一次生效。

防抖Debounce 实现

function debounce(func, delay) {
    var time;
    return function() {
        clearTimeout(time);
        time = setTimeout(() => {
            func.apply(this, arguments);
        }, delay);
    }
}

function resize() {
    console.log("窗口大小被改变");
}
window.addEventListener('resize', debounce(resize, 500));

效果如下所示。

21.gif

节流Throttle 实现

时间戳版实现

function throttle(func, delay) {
    var lasttime = 0;
    return function() {
        var nowtime = Date.now();
        if (nowtime >= delay + lasttime) {
            func.apply(this, arguments);
            lasttime = nowtime;
        } else {
            console.log("---距离上次调用的时间差不满足要求");
        }
    }
}

function resize() {
    console.log("窗口大小被改变");
}
window.addEventListener('resize', throttle(resize, 500));

效果如下所示。

ee.gif

定时器版实现

function throttle(func, delay) {
    var timer = null;
    return function() {
        if (!timer) {
            func.apply(this, arguments);
            timer = setTimeout(() => {
                timer = null;
            }, delay);
        } else {
            console.log("---上一个定时器尚未完成");
        }
    }
}

function resize() {
    console.log("窗口大小被改变");
}
window.addEventListener('resize', throttle(resize, 500));

效果如下所示。

22.gif