JS防抖和节流

  前言

 在网页实际运行的某些场景下,有些事件会不间断的被触发,如scroll事件,而不像我们想象中的,滚动一次触发一次,稍微滚动一下就会触发n多次scroll事件。如下:

window.onscroll = function (){
        console.log(123);
    }  //监听滚动条滑动

 我只是轻微的滚动了一下滚动条就触发了这么多次的scroll事件,这种情况下,由于过于频繁地DOM操作和资源加载,严重影响了网页性能,甚至会造成浏览器崩溃。

 此时,我们可以采用 debounce(防抖)和 throttle(节流)的方式来减少调用频率,同时又不影响实际效果。

 

  防抖

 防抖通过设置setTimeout定时器的方式延迟执行,当快速多次点击的时候,每一次都会重置定时器,只有你一段时间都不点击时定时器才能到达条件并执行事件函数。即如果触发事件后在 n 秒内又触发了事件,则会重新计算函数延执行时间。

 如下,我们模拟一个表单提交的例子,多次快速点击提交后只会执行一次:

<input type="submit" id="btn" value="提交">
<script>
    var btn = document.getElementById('btn');
    // 点击后触发debounce()函数,第一个参数为真实要执行的函数,第二个参数为定时器延迟时间
    btn.addEventListener('click',debounce(submit,1000));
    //真实要执行的函数
    function submit(e){
        console.log("提交成功!");
        console.log(this)
        console.log(e);
    }
    //防抖函数
    function debounce(fn,delay){
        //设置time为定时器
        var time = null;
        //闭包原理,返回一个函数
        return function (e){
            //如果定时器存在则清空定时器
            if(time){
                clearTimeout(time);
            }
            //设置定时器,规定时间后执行真实要执行的函数
            time = setTimeout(() => {//此箭头函数里的this指向btn这个按钮
                fn.call(this,arguments);//改变真实要执行函数的this指向,原submit函数里面的this指向window
            },delay);
        }
    }
</script>

 运行后,狂点提交按钮停下来后只会执行一次,而不会出现多次点击而多次提交。对于代码中的闭包还有箭头函数的this指向问题不清楚的,可以翻看我的这两篇:闭包箭头函数

 

  节流

 节流其实就很好理解了,减少一段时间的触发频率。简单来说,就是你一直狂点不停的话,它会每隔一定时间就执行一次。它与防抖最大的区别就是,无论事件触发多么频繁,都可以保证在规定时间内可以执行一次执行函数。下面利用计算时间戳实现:

<input type="submit" id="btn" value="提交">
<script>
    var btn = document.getElementById('btn');
    // 点击后触发debounce()函数,第一个参数为真实要执行的函数,第二个参数为定时器延迟时间
    btn.addEventListener('click',throttle(submit,500));
    //真实要执行的函数
    function submit(e){
        console.log("提交成功!");
        console.log(this)
        // console.log(e);
    }
    //节流函数
    function throttle(fn,delay){
        //bef为上一次执行时间,初始值为0
        var bef = 0;
        return function (e){
            //获取当前时间戳
            var now = new Date().getTime();
            //如果当前时间减去上次时间大于限制时间时才执行
            if(now - bef > delay){
                console.log(this);
                fn.call(this,arguments);
                bef = now;
            }
        }
    }
</script>

 运行后,狂点不停的话,每隔500毫秒才执行一次。

 也可以用定时器实现节流,如下:

<input type="submit" id="btn" value="提交">
<script>
    var btn = document.getElementById('btn');
    // 点击后触发debounce()函数,第一个参数为真实要执行的函数,第二个参数为定时器延迟时间
    btn.addEventListener('click',throttle(submit,500));
    //真实要执行的函数
    function submit(e){
        console.log("提交成功!");
        // console.log(this)
        console.log(e);
    }
    //节流函数
    function throttle(fn,delay){
        var flag = true;
        return function (e){
            if(flag){
                setTimeout(() => {
                    //到规定时间后执行函数,同时flag=true
                    fn(this,arguments);
                    flag = true;
                },delay);
            }
            //防止一直执行
            flag = false;
        };
    }

</script>

 

  总结

 最后我们也明白了防抖和节流的主要区别,那么他们各自适应的场景又有哪些呢?一般当我们提交表单时使用防抖,但在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。

 

 


 

参考文章:https://bbs.huaweicloud.com/blogs/297720?utm_source=cnblog&utm_medium=bbs-ex&utm_campaign=other&utm_content=content

 

posted @ 2021-11-03 21:14  打遍天下吴敌手  阅读(3783)  评论(0编辑  收藏  举报