JS知识回顾(三):防抖与节流

144 阅读3分钟

防抖与节流

防抖和节流都是为了解决短时间内大量触发某函数而导致的性能问题,比如触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。但二者应对的业务需求不一样,所以实现的原理也不一样。

不处理防抖节流的缺点是:浪费请求资源。

1.  防抖

在事件被触发n秒后再执行回调函数,如果在这n秒内又被触发,则重新计时。

应用场景:

● 输入框,用户输入一连串字符,只会在输入完后去执行最后一次查询的ajax请求,这样可以有效减少请求次数,节约请求资源。

● window的resize、scroll事件,不断地调整浏览器的窗口大小,或者滚动时会触发对应事件,防抖让其只触发一次。

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>防抖</title>
</head>

<body>
    <div>加入防抖后的输入
        <input type="text" name="debounce" id="debounce">
    </div>
</body>
<script type="text/javascript">
    window.onload = function () {
        // 模拟ajax 请求
        function ajax(content) {
            console.log('content: ', content);

        }

        function debounce(fun, delay) {
            return function (args) {
                // 获取函数的作用域与变量
                let that = this
                let _args = args
                //每次事件被触发,都会清除当前的timeer,然后重写设置超时调用
                clearTimeout(fun.id)
                fun.id = setTimeout(function () {
                    fun.call(that, _args)
                }, delay)
            }
        }
        let input = document.getElementById("debounce");
        let debounceAjax = debounce(ajax, 1000)
        input.addEventListener('keyup', function (e) {
            console.log('e.target.value: ', e.target.value);
            debounceAjax(e.target.value)
        })
    }
</script>

</html>

代码说明:

● 每一次事件被触发,都会清除当前的timer,然后重新设置超时调用,即重新计时。这就会导致每一次高频事件都会取消前一次的超时调用,导致事件处理程序不能被触发。

● 只有当高频事件停止,最后一次事件触发的超时调用才能在delay时间后执行。

2.  节流

规定一个单位时间,在这个单位时间内,只能又一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。

应用场景:

● 鼠标连续不断地触发某事件(如点击), 只在单位时间内只触发一次。

● 在页面的无限加载场景下,需要用户在滚动页面,每隔一段时间发一次ajax请求,而不是在用户停下滚动页面操作时才去请求数据。

● 监听滚动事件,比如是否滑到底部自动加载更多,用节流来判断。

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>节流</title>
</head>

<body>
    <div>
        3.加入节流后的输入:
        <input type="text" name="throttle" id="throttle">
    </div>
</body>
<script type="text/javascript">
    window.onload = function () {
        // 模拟ajax请求
        function ajax(content) {
            console.log("aiax 请求", content);
        }

        function throttle(fun, delay) {
            let last, deferTimer
            return function (args) {
                console.log('args: ', args);
                let that = this
                let _args = arguments

                let now = +new Date()
                if (last && now < last + delay) {
                    clearTimeout(deferTimer)
                    deferTimer = setTimeout(function () {
                        last = now
                        fun.apply(that, _args)
                    }, delay)
                } else {
                    last = now
                    fun.apply(that, _args)
                }
            }
        }
        let throttleAjax = throttle(ajax, 2000)
        let inputThrottle = document.getElementById('throttle')
        inputThrottle.addEventListener('keyup', function (e) {
            throttleAjax(e.target.value)
        })

    }
</script>

</html>

3.  总结

防抖是回城,节流是放技能。

回城重新触发就会重新计时。节流是触发一次,几秒后才能再次放技能。

附注:js键盘事件

  1. keydown - 键按下的过程
  2. keypress - 键被按下
  3. keyup - 键被松开

参考链接:juejin.cn/post/695870… juejin.cn/post/684490…