防抖与节流

69 阅读1分钟

我记得之前我能手写的。

talk is cheap,show me the code

思路:总是保留最后一个定时器,这样就可以每次都是最后的时候再执行函数。

<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>
        const ipt = document.querySelector('input');
        //  简单版本
        // 思路就是:每次输入都高频率触发事件,防抖就是 设置一个定时器,只在最后的一次触发,如果前面有定时器就清除掉。

        // let timer =null;
        // ipt.oninput = function(){

        //     if(timer){
        //       clearTimeout(timer);
        //     }
        //     timer=setTimeout(()=>{
        //         console.log(this.value);
        //     },500);
        // }

        // 封装防抖函数
        const onDebounce = (fn, delay) => {
            let timer = null;
            // 这里返回函数,主要是ipt.oninput之前也调用一个函数,this指向ipt
            // 再然后就是闭包,让timer得以变量引用,保存局部变量。
            return function () {
                if (timer) {
                    clearTimeout(timer);
                }
                timer = setTimeout(() => {
                    fn.call(this);
                }, delay);
            }
        }
        //    ipt.oninput = onDebounce(function(){
        //     console.log(this.value);
        //    },500)
        ipt.addEventListener('input', onDebounce(
            function () {
                console.log(this.value);
            }, 500
        ))
    </script>
</body>

</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 style="height:2000px">
    <script>
        // 定时器器方式
        // function throttle(fn, delay) {
        //     // 初始设置为真,设置一个定时器
        //     let valid = true;
        //     return function () {
        //         // 函数内局部作用域,可访问外部valid。
        //         // 之后valid重新赋值后,优先使用局部作用域内的valid;
        //         if (!valid) {
        //             return;
        //         }
        //         valid = false;
        //         setTimeout(() => {
        //             fn();
        //             // 定时器生效后重新设置一个定时器
        //             valid = true;
        //         }, delay)
        //     }
        // }


        // 时间戳方式
        function throttle(fn, delay) {
            let previous = 0;
            return function () {
                let now = new Date().getTime();
                if (now - previous > delay) {
                    fn.call(this);
                    previous = now;
                }
            }

        }

        function showTop() {
            var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
            console.log('滚动条位置:' + scrollTop);
        }
        window.onscroll = throttle(showTop, 1000);
    </script>
</body>

</html>

参考资料:

segmentfault.com/a/119000001…

www.bilibili.com/video/BV1SU…