防抖和节流

218 阅读3分钟

防抖和节流就是为了限制函数执行的次数,减少请求量,进行优化。

防抖(debounce)

什么是防抖?

触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。

例子:

鼠标进入box内移动,每次移动都+1

 <style>
        .box {
            width: 100%;
            height: 300px;
            background-color: plum;
            font-size: 20px;
            text-align: center;
            line-height: 300px;
        }
    </style>
    
        <div class="box">0</div>
        
<script>
        let count = 0;
        let box = document.querySelector(".box");
        function move() {
            box.innerHTML = count++;
        }
        box.onmousemove = move;
</script>

图片.png

高频触发事件,当鼠标进入盒子内之后,每移动一次,就会让box中的数字+1,非常的耗性能。

使用防抖函数,在1s内没有再次的进行移动鼠标,时间结束后,才会输出;如果在1s内继续移动鼠标,则时间会重新计时,再次从1s开始计算,直到没有移动的操作,才会输出。

封装函数

        function debounce(fn) {
            let time = null; //设置定时的名字,通过闭包进行保存名字
            return function () {
                clearTimeout(time);  // 让前一个定时器 清除掉 重新计算时间
                // 如果只用定时器 只是起到了 延迟输出的作用
                time = setTimeout(function () {
                    // this 改变this指向,指向当前作用的对象box
                    // arguments  指向event对象
                    fn.apply(this,arguments);
                }, 1000)
            }
        }
        
        
        // 调用函数,每次移动都调用debounce函数,清除上次的定时器,在重新赋值一个定时器,用来计算时间
        box.onmousemove = debounce(move);
        

事件响应函数(move函数)在一段时间后(1000ms)才执行

如果在这段时间内(1000ms内)再次调用,则会重新计算执行时间。

当预定时间内(1000ms),没有再次调用该函数 则会执行事件函数(move函数)

延后的概念

节流(throttle)

什么是节流?

高频事件触发,但是在n秒内只会执行一次,所以节流会稀释函数的执行频率

(可以简易理解成节流阀,当设置节流阀之后,在规定的时间内,不能执行下次的函数程序。)

举个例子:

改变窗口大小的时候,让body的背景颜色也随之改变。

    <script>
        function color() {

            let r = Math.floor(Math.random() * 255);
            let g = Math.floor(Math.random() * 255);
            let b = Math.floor(Math.random() * 255);
            document.documentElement.style.backgroundColor = `rgb(${r},${g},${b})`
        }
        window.onresize=color;
    </script>

执行效果是每改变一次,就改变body的背景颜色;当快速改变的时候,颜色变换的很快,影响体验。

所以 使用节流函数 来对代码进行优化。

节流函数封装


   function throttle(fn,dealy) {
            let isTrue = true;//通过闭包设置的一个标记,为公用的
            return function () {
                if (!isTrue) return;// 判断标记是否为true,不为true就不执行下面的代码
                isTrue = false;// 进来之后,使标记变为false,在定时器没有执行完之前,改变窗口大小函数不执行
                setTimeout(() => {
                    fn.apply(this, arguments);
                    //关键在第一个参数,为了确保上下文环境为当前的this,所以不能直接用fn。
                    isTrue = true;// 执行完之后变为true,以方便进行下一个的调用
                }, dealy)
            }
        }
        
        //  函数调用
        window.onresize = throttle(color,2000);


可以在函数封装中在设置一个dealy参数,用于自己设置需要等待的时间。

应用的场景:

  • 滚动事件
  • resize事件,浏览器窗口缩放
  • 搜索框输入查询
  • 表单验证
  • 按钮提交事件
  • ....