防抖和节流

122 阅读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>second</title>
</head>
<body>
    <input type="text" id="inputid" />

    <script>
        // 操作不直接触发,搞个定时器,下次触发时再重新定时
        // 封装成一个防抖工厂,传入一个函数告诉它要给哪个操作进行防抖,以及防抖的延时是多久,这样就能复用它
        function debounce(fn, delay) {
            let timer = null;
            // return出一个新的加了防抖操作的函数
            // 如果一直调用,防抖会将先前的时间都清掉,直到停下来后过delay时长后再触发
            return function() {
                // setTimeout(), setInterval()会返回一个ID,可将ID传给clearTimeout(), clearInterval()以取消执行
                clearTimeout(timer);
                timer = setTimeout(() => {
                    fn.apply(this, arguments);
                }, delay);
            }
        }

        let inputdom = document.getElementById("inputid");
        // 原函数
        // inputdom.oninput = function(event) {
        //     console.log(event.target.value);
        // }
        // 改造input监听实现,将输入监听变成防抖的,联想输入会更科学
        inputdom.oninput = debounce(function(event) {
            console.log(event.target.value);
        }, 500);
    </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>throttle</title>
</head>
<body>
    <input id="inputid" />
    <button id="sendAxios">请求</button>
    <script>
        let inputdom = document.getElementById("inputid");
        // 写个节流工厂函数,方便后续调用
        function throttle(fn, delay) {
            // 定义阀门
            let valid = true;
            return function() {
                if (valid) {
                    setTimeout(() => {
                        fn.apply(this, arguments);
                        valid = true;
                    }, delay);
                    valid = false;
                } else {
                    // 若阀门本来就是关的,那就不进行操作,return个false
                    return false;
                }
            }
        }
        inputdom.oninput = throttle(function(event) {
            console.log(event.target.value);
        }, 200);
    </script>
</body>
</html>

防抖和节流的对比

相同点

  • 都是为了阻止操作高频触发,从而浪费性能。

区别

  • 防抖:让你多次触发,只生效最后一次。适用于我们只需要一次触发生效的场景。
  • 节流:让你的操作,每隔一段事件才能触发一次。适用于我们多次触发要多次生效的场景。