JavaScript防抖和节流

2,574 阅读2分钟

前言

在进行窗口的resize、scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。此时我们可以采用debounce(防抖)和throttle(节流)的方式来减少调用频率,同时又不影响实际效果。

它们都是有一个时间规定,在这个规定下限制某个方法的执行时机。
它们有个共同点,就是指定时间内,只能执行一次。

防抖

 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

举个例子:
当鼠标移动到一个div上时,div的内容一直在更新,如果不用防抖处理,效果如下图

 var mydiv = document.getElementById('mydiv');
        let count = 0;
        function myEvent(){
            mydiv.innerText = count++;
        }
        mydiv.addEventListener('mouseover', function(event){
            myEvent();
        });

使用了防抖后的效果

 function debounce(fn,delay) {
            let timeout = null;
            return function () {
                if(timeout){
                    clearTimeout(timeout);
                }
                timeout = setTimeout(() => {
                    fn.apply(this, arguments);
                },delay);
            }
        }
        var mydiv = document.getElementById('mydiv');
        let count = 0;
        function myEvent(){
            mydiv.innerText = count++;
        }        
        mydiv.addEventListener('mouseover', debounce(myEvent,2000));

代码实现原理:
函数防抖的关键在于,在一个动作发生一定时间后,才执行指定事件;如果n秒内高频事件再次被触发,则重新计算时间;

在document中鼠标移动的时候,会在mouseover最后触发的2s后执行回调函数myEvent;如果我们一直在浏览器中移动鼠标(比如10s),会发现会在10 + 2s后才会执行myEvent函数(因为clearTimeout(timeout)),这个就是函数防抖。

节流

规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。稀释事件执行频率。

定时器的实现方式

 function throttle(fn, delay) {
                let hasRun = false;
                return function () {
                    if (hasRun) {
                        return;
                    }
                    hasRun = true;
                    setTimeout(() => {
                        hasRun = false;
                        fn.apply(this, arguments);
                    }, delay);
                }
        }
        var mydiv = document.getElementById('mydiv');
        let count = 0;
        function myEvent(){
            mydiv.innerText = count++;
        }        
        mydiv.addEventListener('mouseover', throttle(myEvent,2000));

效果图:

时间戳的实现方式

let div = document.querySelector('div');
var count = 0;
function myEvent() {
    div.innerText = count++;
}
div.onmouseover = throttle(myEvent,2000);
function throttle(func, wait) {
    let pre = 0;
    return function () {
        let now = new Date().getTime();
        if (now - pre > wait) {
            pre = now;
            func.apply(this);
        }
    }
}

代码实现原理:每隔n秒执行一次回调函数。

应用场景

防抖:
1、search搜索联想,用户在不断输入值时,用防抖来节约请求资源;
2、window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次;
3、防止重复提交;
节流:
1、鼠标不断的点击触发,mousedown(单位时间内只触发一次);
2、监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断;