JS防抖、节流的原理和实现过程

        我们在写项目中总会遇到一些情况,就是在设置了一些监听事件后,你会发现这个事件触发太容易、太频繁了。比如我们监听浏览器滚动,并且每次触发了浏览器滚动事件就输出下提示。

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

<body>
    <div style="height: 8600px;"></div>
    <script>
        window.onscroll = function () {
            console.log('你滚动了');
        }
    </script>
</body>

</html>

但你会发现,只要轻轻一滚动鼠标滚轮,就会输出十几条信息,触发频率太高了。

       在上面例子监听事件只是简单的输入,还好浏览器可以完全胜任这个工作。但如果我们监听事件是非常复杂的请求,或者有些人非常喜欢点击按钮(疯狂点几十下那种),而这个按钮是请求事件的按钮,每点击一次按钮就会发送一次请求,浏览器一下子进行这么多的请求,多累啊,总会把浏览器累死的(卡死)。

         所以你就要防止这个人手抖(防抖),不要他点这么多下鼠标。

1.防抖

 防抖:监听的元素被触发的时候,不会立刻执行监听函数,而是等待一段时间(自己定义的时间),如果等待的这段时间内元素没有再被触发过了,就执行监听函数。如果等待的这段时间内元素又被触发了,又重新等待一段时间,就这样重复重复,直到元素没有再被触发了,再执行函数。说白了就像是电梯关门,一直有人在就不会关门,没有人了过一会就会自动关门。

例子:对按钮的点击事件进行防抖。

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
</head>

<body>
    <button id="btn">点击一下</button>
    <script>
        //获取到按钮的dom
        var btn = document.getElementById('btn')
     
        function showTip() {
            console.log('你点击了我');
        }

        //防抖的实现用到了闭包可以访问到外部函数的变量,而且这个变量不会被垃圾回收机制处理
        //所以timer这个变量可以存储上次事件触发的定时器。
        function debounce(fun, delay) {
            let timer;//这个变量用来表示定时器
            return function () {
                //如果事件又被触发了,我们清空timer,timer表示上一次的定时器
                //这个上一次的定时器timer我们利用闭包存储的
                clearTimeout(timer);
                //注意:setTimeout()会返回一个唯一的值,可以表示当前这个定时器
                //我们用timer存储setTimeout()的返回值
                //然后我们重置定时器
                timer = setTimeout(() => {  
                    fun()
                }, delay)
            }
        }
        //给按钮绑定监听函数,这个函数的参数需要一个回调函数,和一个等待时间。
        btn.onclick = debounce(showTip, 2000)
    </script>
</body>

</html>

2.节流

 节流:功能和防抖有点相似,也是在触发一段时间后才执行函数,但是有一点不一样。防抖是等元素没有再被触发了才执行函数,感觉这样白白等下去有点傻呀,而节流就是在某个时间间隔之后就会执行监听函数。

说白了,有个人疯狂点击鼠标触发事件的时候,如果你用防抖,要等他疯狂点击后才会执行函数,这个人都在疯狂点击鼠标了,肯定很着急鸭,他可能等不到你执行监听函数就关闭你网站了,然后心里想着‘垃圾网站’。所以用节流就可以在他疯狂点击鼠标期间的一段时间内,执行监听函数,既考虑了浏览器,又考虑了用户。

例子还是按钮点击事件:

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

<head>
    <title>Document</title>
</head>

<body>
    <button id="btn">点击一下</button>

    <script>

        var btn = document.getElementById('btn')

        function showTip() {
            console.log('你点击了我');
        }

        function throttling(fun, delay) {
            //还是利用闭包的特性来储存上次的定时器timer
            let timer;
            return function () {
                let context = this;//这是为了防止fun中this改变了
                let args = arguments;//防止fun中的参数因为闭包无了
                //如果上次的定时器还存在就直接返回了,因为是间隔时间内才输出一次
                //如果定时器存在,表示这段时间间隔内已经输出过了
                if (timer) { 
                    return;
                }
                //如果上次定时器结束了,就重新设置定时器
                timer = setTimeout(() => {
                    fun.apply(context, args)//利用apply改变fun的this指向
                    timer = null;//上一次的定时器就置空就行
                }, delay)
            }
        }

        btn.onclick = throttling(showTip, 1000)
    </script>
</body>

</html>

另一种写法,利用Date函数,通过上次触发事件的时间和这次触发事件的时间差,进行判断,然后节流。

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

<head>
    <title>Document</title>
</head>

<body>
    <button id="btn">点击一下</button>
    <script>
        var btn = document.getElementById('btn')
     
        function showTip() {
            console.log('你点击了我');
        }

        function throttling(fun, delay) {
            let old = 0;
            return function () {
                let context = this;
                let args = arguments;
                //now变量表示当前点击时的时间戳,这个值很大
                let now = new Date();
                if (now - old > delay) {
                    fun.apply(context, args)
                    old = now;//改变old的值,并且old值利用闭包特性储存着
                }
            }
        }

        btn.onclick = throttling(showTip, 1000)
    </script>
</body>

</html>

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值