← 返回首页
Javascript基础教程(五十)
发表时间:2021-12-24 16:54:01
防抖与节流

1.防抖(debounce)

防抖策略 (debounce)当事件被触发时,延迟N秒才执行,如果在这N秒内再次被触发将重新计时。

防抖的应用场景:用户在很短的时间内连续点击表单按钮,频繁的执行回调导致数据的不一致性。

==用简单的话来说,防抖就是只执行最后一次。==

防抖实现的基本思路: 在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms,然后:

效果:如果短时间内大量触发同一事件,只会执行一次函数。

实例:

data.json

{
  "code": 200,
  "msg": "success"
}

demo.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>防抖与节流</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>

<div>
    <button id="bt1">未添加防抖功能</button>
    <br>
    <br>
    <button id="bt2">已添加防抖功能</button>
    <br>
</div>
<script>
    let timer = null

    $("#bt1").click(() => {
        //console.log("btn1 is clicked...")
        $.ajax({
            url: 'data.json',
            type: 'get',
            success: resp => console.log(resp)
        })
    });

    $("#bt2").click(() => {
        //console.log("btn2 is clicked...")
        if (timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(() => {
            $.ajax({
                url: 'data.json',
                type: 'get',
                success: resp => console.log(resp)
            })
        }, 2000)
    });
</script>
</body>
</html>

执行效果: 快速点击按钮1,会频繁执行回调。如下图:

快速点击按钮2,在两秒内仅仅执行一次。如下图:

2.节流(throttle)

节流可以减少一段时间内事件的触发频率。

==简单来说节流就是控制事件触发的次数。==

实现节流其实很简单:我们可以设计一种类似控制阀门一样定期开放的函数,也就是让函数执行一次后,在某个时间段内暂时失效,过了这段时间后再重新激活(类似于技能冷却时间)。

如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效。

首先下面有一段这样的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>防抖与节流</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>

<div>
    <br>
    <br>
    <br>
    <br>
    <br>
    <br>
</div>
<script>
    window.addEventListener('scroll',function(){
        console.log('scrolling...');
    });
</script>
</body>
</html>

执行效果: 每次滚动都会触发这个事件,但是仅仅几秒钟就已经触发了一两百次,那如果是和后台交互数据的话,这样的频率和数据量会占很多带宽,会很耗性能。那么我们就会想到,能不能让它的执行次数减少,这个就是节流的初衷。

有了最初始的问题了,那么现在就来解决问题! 解决这个问题,会用到一个 开关思想 那么代码如下:

let flag = true;
window.addEventListener('scroll', function () {
     if(flag){
         setTimeout(()=>{
             console.log('scrolling...');
             flag = true;
         },1000);
     }
     flag = false;
     //console.log('scrolling...');
});

进一步优化代码,将全局变量去掉,进行一个优化,进行封装,代码如下:

    window.onscroll = throttle(function () {
        console.log('scrolling');
    }, 1000)

    function throttle(fn, delay) {
        var flag = true;
        return function () {
            if (flag) {
                setTimeout(() => {
                    fn.call(this)
                    flag = true;
                }, delay);
            }
            flag = false;
        }
    }

每次经过1000ms打印一次,(时间根据所需更改)这样就解决了事件的触发频率过快的情况。

3.loadash.js实现防抖和节流

Lodash是一个一致性、模块化、高性能的 JavaScript实用工具库。里面提供了debounce/throttle函数。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--引入鲁大师库-->
    <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
</head>
<body>

<div>
    <button id="btn">点我</button>
</div>

<script>

    function test(){
        console.log('点你妹啊....')
    }
    document.getElementById("btn").addEventListener("click",_.debounce(test,1000));
</script>
</body>
</html>