通俗易懂实现防抖与节流

80 阅读2分钟

防抖与节流

防抖

防抖的实现目的是为了防止一个事件过于频繁的触发降低性能,举一个最简单的例子input事件,每一次输入内容都会向后台发送请求,如图:

1651580094410.png

防抖就是可以很好的解决这个问题,首先我们的目的是为了获取输入框中最后一次输入的内容,所以我们可以添加一个一秒的延迟器,来获取到最后一次输入的内容

<!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>Document</title>
</head><body>
    <input type="text">
    <script>
        let inp = document.querySelector('input')
        let timeId
        inp.addEventListener('input', function () {
            //定时器不为空则清除定时器
            if (timeId !== null) {
                clearTimeout(timeId)
            }
            //一秒后获取输入的value值
            timeId = setTimeout(() => {
                console.log(this.value);
            }, 1000);
        })
    </script>
</body></html>

这个问题虽然解决了,但是并不能进行业务开发,我们可以运用闭包来封装一个防抖的方法

        let inp = document.querySelector('input')
        inp.addEventListener('input', debounce(function () {
            //this指向了window
            console.log(this.value);
        }, 1000))
        //闭包进行防抖的功能封装
        //fn为上面传入的函数 delay为延迟时间
        function debounce(fn, delay) {
            let timeId
            return function () {
​
                //定时器不为空则清除定时器
                if (timeId !== null) {
                    clearTimeout(timeId)
                }
                //一秒后获取输入的value值
                timeId = setTimeout(() => {
                    //需要改变this指向,inp调用了fn所以指向改为了inp
                    fn.call(this)
                }, delay);
            }
        }

结果如图: image.png

节流

节流的实现目的与防抖一样都是为了阻止一个事件频繁的触发,最常用的场景就是页面滑轮滚动时触发scroll事件,如图:

image.png

我们的目的是控制滚轮事件的执行次数,所以我们可以添加一个一秒的延迟器,一秒内只能获取到一次的数据。

<!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>Document</title>
    <style>
        body {
            height: 2000px;
        }
    </style>
</head><body>
    <script>
        let flag = true
        window.addEventListener('scroll', function () {
            if (flag) {
                setTimeout(() => {
                    console.log('swh');
                    flag = true
                }, 1000)
            }
            flag = false
        })
    </script>
</body></html>

同样进行函数封装

       window.addEventListener('scroll', throttle(function () {
            //this指向了window
            console.log('swh');
        }, 1000))
        //闭包进行节流的功能封装
        //fn为上面传入的函数 delay为延迟时间
        function throttle(fn, delay) {
            let flag = true
            //定时器不为空则清除定时器
            return function () {
                //判断改变进入定时器的次数
                if (flag) {
                    setTimeout(() => {
                        //这个案例可不写call,因为指向都为window,但为了以后的业务开发写上
                        fn.call(this)
                        flag = true
                    }, delay)
                }
                flag = false
            }
        }

结果如图

image.png