深入学习JS — 一篇文章了解JS的节流与防抖

1、节流(throttle)

什么是节流?
规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。
一般使用setTimeout函数实现。

我的理解是“节流”大概就是节省流量的意思,本质是让一个方法在我们预设的时间里
只运行一次,然后在我们规定的时间内,即时再次触发,也不会运行对应的函数。

常见应用场景:

鼠标不断点击触发,click/mousedown(单位时间内只触发一次)
监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断

(1)、未设置节流

按钮点击事件没有设置节流:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>throttle</title>
</head>

<body>
    <button onclick="clickMe()">点我</button>
    <script>
        function clickMe(){
            console.log('点击了一次按钮!');
        }
    </script>
</body>

</html>

效果:
在这里插入图片描述
可以看到,我不断的点击按钮,会一直触发clickMe()函数。如果clickMe函数中包含了请求服务器的事件,例如刷新当前数据,那么这样显然是不太合理的,如果用户不断的点击刷新按钮,那么服务器可能就会奔溃了!

最常见的节流是通过函数闭包配合setTimeout实现的,我们知道:

闭包返回的函数所调用的变量不会被销毁,所以可以在函数中定义一个flag,
用来记录函数是否在单位时间内被触发。

(2)、实现节流

下面简单实现按钮点击事件的节流操作 :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>throttle</title>
</head>

<body>
    <button onclick="throttleClick()">点我</button>
    <script>
        function throttle(fn, delay) {
            let flag = false
            return function () {
                if (flag) {
                    //什么都不做
                    return;
                } else {
                    //执行函数
                    fn()
                    //执行了函数 需要一段事件冷却 将flag社会true 下次调用throttle函数, 会什么都不做。
                    flag = true
                    setTimeout(() => {
                        //delay时间后 冷却好了 将flag设为false 下次调用函数 触发fn
                        flag = false
                    }, delay)
                }
            }
        }
        function clickMe(){
            console.log('点击了一次按钮!');
        }
        const throttleClick = throttle(clickMe, 3000)
    </script>
</body>

</html>

效果:

在这里插入图片描述
可以看到,我疯狂的点击按钮,第一次点击,触发了函数。然后后面持续的点击,并没有触发函数。三秒后,我还在点击,那么再次触发函数。

最核心的原理就是闭包会让flag变量一直存在,那么它的状态便一直保留这,所以我们可以根据flag来判断应不应该运行fn函数。利用setTimeout函数,延时自动改变flag的状态,从而实现规定时间后,点击按钮才能运行fn方法。

2、防抖(debounce)

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

最常见的例子就是输入框输入关键词,底部会出现关联词列表,这是因为程序检测到我们输入内容后,就会利用我们的输入内容调用后端接口,来模糊查询与之相关的关联词。

下面我们通过一个简单的检测输入框输入程序,来看看防抖的作用:

(1)、未设置防抖

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>debounce</title>
</head>

<body>
    <input type="text" name="" id="" oninput="search(event)" onporpertychange="search(event)">
    <script>
        function search(e){
            //获取输入的词语 实际应用中应该会进行ajax请求
            console.log(e.target.value)
        }
    </script>
</body>

</html>

效果:

在这里插入图片描述
可以看到,我不断的输入内容,每输入一个词,便会触发一次search()函数。实际应用中,search()函数应该会调用后端的接口,来请求与之匹配的关联词。所以如果我输入一个词便就请求一次,显然增加服务器的压力。那么如果我输入几个词以后,再去请求,就会好很多。

(2)、设置防抖

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>debounce</title>
</head>

<body>
    <input type="text" name="" id="searchInput" oninput="search(event)" onporpertychange="search(event)">
    <script>
        function debounce(fn , delay){
            let timer = null;//设置定时器
            return function(...args){
                //再次触发 清除计时器 重新创建新的计时器
                clearTimeout(timer);
                //创建新的计时器
                timer = setTimeout(()=>{
                    fn(args);
                },delay)
            }
        }
        //模拟请求的函数
        function ajax(content){
            console.log('模拟请求:' + content);
        }

        let searchDebounce = debounce(ajax, 1000);
        //输入触发的事件
        function search(e){
            searchDebounce(e.target.value);
        }
    </script>
</body>

</html>

效果:

在这里插入图片描述
可以看到:

我输入“ 1 ”,停顿一秒,根据“ 1 ”发起了请求,同理再次输入“ 2 ”,1秒后发起了关于“ 12 ”的请求,然后同理1秒后发起“123”的请求。但是,当我输入“123”后,之后疯狂地输入“3”,可以看到一直没有发起请求,说明我们已经达到了防抖的目的了。当我停止输入“3”后,1秒后,发起了所输入的一大串的请求。

3、节流与防抖的区别

我最开始的理解是:

节流就是事件一触发就调用对应的处理函数,然后在规定时间内,再次触发事件也不会调用处理函数了。
防抖就是触发事件后,规定时间以后才会执行处理函数。

在我阅读了许多关于防抖和节流的文章博客之后,发现自己的理解太过片面了。

(1)、节流和防抖的调用函数的时间可以是事件一触发就调用,也可以是规定时间后再调用,可以根据实际需求修改函数达到目的。
(2)、防抖与节流的概念:

节流:指定时间间隔内只能触发一次任务。

防抖:事件频发触发的情况下,只有任务触发的间隔超过指定间隔时,任务才会触发。

(3)、节流与防抖的区别:

通过上面的按钮点击的节流实现和关联词搜索的防抖实现,可以看出,二者的区别:
(1)、节流是在规定间隔时间内,我一直触发事件,只会去调用一次处理函数。我不停地点击按钮,每3秒只会调用一次处理函数(例如刷新页面操作)。在上述例子中,3秒内,只有第一次点击事件有效。3秒后,如果再次点击,也是第一次点击有效。
(2)、防抖是在规定间隔时间内,我不停的触发事件,那么就一直不会调用处理函数。上面的关联词搜索例子中,如果我每次输入的间隔小于1s(delay),那么一直都不会触发请求函数,因为只要在1s内触发防抖函数,那么正在计时的计时器就会被销毁,并创建一个新的1s的计时器。直到我停止输入1s后,setTimeout函数中的请求函数才能被调用,发起请求。

所以结合实际应用是比较好理解节流和防抖的区别的。以上内容是我关于节流与防抖的理解,如果有错误的地方,麻烦指正!

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小绵杨Yancy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值