防抖和节流

防抖

概念

某个函数,在某段时间内,无论触发了多少次,都只执行最后的一次。

实现原理

利用定时器

/*
 * 防抖函数
 * @param fn 事件触发的操作
 * @param delay 多少毫秒内连续触发事件,不会执行
 * @returns {Function}
 */
function debounce(fn, delay) {

    let timer = null;

    return function () {
        let args = arguments;
        let that = this;

        if (timer) {
            clearTimeout(timer);
        }

        timer = setTimeout(function () {
            fn.apply(that, args);
        }, delay);
    }
}

使用场景

用户在短时间内,多次点击登陆,发送短信,等请求数据的操作。

文本编辑器一段时间不操作,进行自动保存。

搜索框进行联想,用户不断输入值,只在停顿1s时才发送请求,进行联想。

<!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>防抖和节流</title>

</head>
<body>
    <input type="text" id="search" value="">
    <script>
        /*
         * 防抖函数
         * @param fn 事件触发的操作
         * @param delay 多少毫秒内连续触发事件,不会执行
         * @returns {Function}
         */
        function debounce(fn, delay) {

            let timer = null;

            return function () {
                let args = arguments;
                let that = this;

                if (timer) {
                    clearTimeout(timer);
                }

                timer = setTimeout(function () {
                    fn.apply(that, args);
                }, delay);
            }
        }

        var input = document.getElementById('search');

        function getData() {
            var keyword = input.value;
            console.log('输入框关键词是' + keyword + ',正在发送请求,从服务器查找该关键词');
        }

        // 设置防抖,无操作后的1秒后,才去触发getData事件。
        // 如果1秒内连续输入,会不断重置定时器,不会触发getData事件
        input.onkeyup = debounce(getData, 1000);
    </script>
</body>
</html>

节流

概念

节流与反抖相反,在某段时间内,无论触发了多少次,都只执行最初的一次。

类型

节流有多种不同应用场景的表现形式,一般可以分为三种,分别是首节流,尾节流,兼顾型节流。

首节流

在某段时间内,无论触发了多少次,都只执行最初的一次。

<!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>首节流</title>

</head>
<body>
    <button id="btn">提交表单</button>
    <script>
        /**
         * 首节流
         * @param fn 事件触发的操作
         * @param delay 多少毫秒内连续触发事件,执行第一次
         * @returns {Function}
         */
        function throttle(fn, delay) {
            let last = 0;

            return function() {
                let now = Date.now();

                if (now - last > delay) {
                    fn.apply(this, arguments);
                    last = now;
                }
            }
        }

        var btn = document.getElementById('btn');

        function submitData() {
            console.log('向服务器提交表单');
        }

        // 两秒内连续提交表单,只执行第一次
        // 连续点击,每两秒才可以触发一次submitData事件
        btn.onclick = throttle(submitData, 2000);
    </script>
</body>
</html>

尾节流

尾节流中,第一次是不会直接执行的,而是在一段时间后再执行。

<!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>尾节流</title>

</head>
<body>
    <button id="btn">提交表单</button>
    <script>
        /**
         * 尾节流
         * @param fn 事件触发的操作
         * @param delay 多少毫秒之后触发事件
         * @returns {Function}
         */
        function throttle(fn, delay) {
            let timer = null;

            return function () {
                let context = this;
                let args = arguments;

                // 给第一次的点击,设置定时任务
                if (!timer) {
                    timer = setTimeout(function () { 
                        fn.apply(context, args);
                        timer = null;
                    }, delay);
                }
            }
        }

        var btn = document.getElementById('btn');

        function submitData() {
            console.log('向服务器提交表单');
        }

        // submitData事件总是会延迟2秒执行
        // 连续点击,每2秒触发一次submitData事件
        btn.onclick = throttle(submitData, 2000);
    </script>
</body>
</html>

兼顾型节流

兼顾型节流,就能够在第一次,最后一次都执行代码。

经过我的测试,兼顾型节流想要在第一次和最后一次都执行代码,必须在delay的时间内,连点按钮两次。

否则,只触发第一次。

function throttle(fn, delay) {
    let last = 0;
    let timer = null;

    return function () {
        let now = Date.now();
        let reming = delay - (now - last);

        clearTimeout(timer);

        if (reming < 0) {
            fn.apply(this, arguments);
            last = now;
        } else {
            timer = setTimeout(() => {
                fn.apply(this, arguments);
            }, reming);
        }
    }
}

学习参考:https://juejin.cn/post/6966951653731729421

posted @ 2022-09-20 09:32  笔下洛璃  阅读(61)  评论(0编辑  收藏  举报