防抖和节流 yinshibanxian

一、防抖

所谓防抖,就是指触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行时间.

举个例子,在下列代码中,div绑定了mousemove事件,当鼠标在div区域中移动的时候会持续的去触发该事件导致频繁执行函数。

<div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div>
<script>
    let num = 1;
    let content = document.getElementById('content');

    function count() {
        content.innerHTML = num++;
    };
    content.onmousemove = count;
</script>

防抖函数

function debounce(func,wait) {
        let timer;
        return function() {
            // 获取this和参数
            // 让返回的函数this指向不变以及依旧能接收到e参数
            let context = this;
            let args = arguments;
            if(timer) clearTimeout(timer);
            timer = setTimeout(() => {
                func.apply(context,args);
            },wait)
        }
    }

我们依然使用上述绑定mousemove事件的例子,通过上面的防抖函数,我们可以这么使用

content.onmousemove = debounce(count,1000);

可以看到,在触发事件1s后,函数才执行,如果我在触发事件1s内又触发了该事件,则会重新计算函数执行时间。

二、节流

所谓节流,是指连续触发事件但是在n秒内只执行一次函数。节流会稀释函数的执行频率。

对于节流,一般有两种方式可以实现,分别是时间戳版和定时器版。

时间戳版

function throttle(func,wait) {
        let previous = 0;
        return function() {
            let context = this;
            let args = arguments;
            let now = Date.now();
            if(now - previous > wait) {
                func.apply(content,args);
                previous = now;
            }
        }
    }

使用方法:

content.onmousemove = throttle(count,1000);

可以看到,在持续触发事件的过程中,函数会立即执行,并且每1s执行一次。

定时器版

    function throttle(func,wait) {
        let timer;
        return function() {
            let context = this;
            let args = arguments;
            if(!timer) {
                timer = setTimeout(() => {
                    timer = null;
                    func.apply(context,args);
                },wait)
            }
        }
    }

使用方法同上,可以看到,在持续触发事件的过程中,函数不会立即执行,并且每1s执行一次,

在停止触发事件后,函数还会再执行一次。

三、防抖和节流的应用场景

  • 防抖
    • search搜索联想,用户在不断输入值时,用防抖来节约请求资源
    • window触发resize的时候,不断地调整窗口大小会不断地触发这个事件,用防抖来让事件只触发一次
  • 节流
    • 鼠标不断点击触发,mousedown(单位事件内只触发一次)
    • 监听滚动事件,比如是否滑动到底部加载更多,用节流来判断