js 防抖、节流

2024-01-19  本文已影响0人  简单tao的简单

一. 概念

防抖:顾名思义,防止抖动,指连续调用时,只有最后一次生效。
节流:节省流量,固定时间间隔触发一次,减小频率。

二. 举例:

  1. 搜索功能,在用户输入结束以后才开始发送搜索请求,可以使用函数防抖来实现;
  2. 验证账号密码功能,在用户输入密码结束以后才开始发送验证请求,可以使用函数防抖来实现;

简单来说:某件事你并不想它太过频繁触发,那么设置一个定时器,每次进来的时候都清除原本的定时器,然后重新开始计时。

  1. 你不想频繁为你女票买单,于是约好每月清空购物车1次
  2. 防止过快拖动滚动条,导致 JS 跟不上拖动频率,通过节流限制每秒触发监听的次数(固定时间固定频率)

简单来说:年轻人要保持一日三餐,规律作息,那就通过节流来限制。

三. 手写防抖、节流思路

1. 首先函数需要哪些参数?

现在,我们可以写出防抖和节流函数的基本结构和参数:

// 防抖
function debounce(fn, wait=500) {
    return function () {
    }
}
 
// 节流
function throttled(fn, wait=500) {
    return function () {
    }
}

2. 原函数的执行条件是什么?

综上,我们可以大致写出函数的执行时机,结构如下:

// 防抖
 
function debounce(func, wait=500) {
    let timeout;
    return function () {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
         // 原函数执行部分
        }, wait);
    }
}
 
 
// 节流
 
function throttle(fn, wait = 500) {
    let timer = null
    return function () {
        if (!timer) {
            timer = setTimeout(() => {
              // 原函数执行部分
            }, wait);
        }
    }
}

3. 原函数执行

我们只需要直接调用fn,即fn()即可。但这样不够完善,需要注意两点:

故而,我们应该努力让新旧函数在这两方面保持一致。

// 防抖
function debounce(func, wait=500) {
    let timeout;
    return function (...args) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
            fn.apply(this, args)
        }, wait);
    }
}
 
// 节流
function throttle(fn, wait=500) {
    let timer = null
    return function (...args) {
        if (!timer) {
            timer = setTimeout(() => {
                fn.apply(this, args)
            }, wait);
        }
    }
}

注1:setTimeout回调中使用arguments:
若不是箭头函数,接收的是回调的实际参数,而不是新函数的实际参数。
若是箭头函数,由于箭头函数没有arguments对象,接收的就是新函数的实际参数。
注2:setTimeout回调中使用this:
若是箭头函数,由于箭头函数没有this,因此回调中的this是外层的this,
若不是箭头函数,回调中的this指向window。

4. 计时器何时重置?

在上面的代码中,防抖和节流何时进行计时器的重置呢?

故针对节流函数,增加清除操作,即增加timer=null重置语句:

// 防抖
function debounce(func, wait=500) {
    let timeout;
    return function (...args) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
            func.apply(this, args)
        }, wait);
    }
}
 
// 节流
function throttle(fn, wait = 500) {
    let timer = null
    return function (...args) {
        if (!timer) {
            timer = setTimeout(() => {
                fn.apply(this, args);
                timer = null;
            },wait);
        }
    }
}

详情参考

完整的防抖用例

<body>
    <button id="debounce">点我防抖!</button>
<script>
    // 防抖
    function debounce(func, wait = 500) {
        let timeout = null;
        return function (...args) {
            clearTimeout(timeout)
            timeout = setTimeout(() => {
                func.apply(this, args)
            }, wait);
        }
    }
    function sayDebounce() {
        console.log(this);
        console.log("防抖成功!");
    }

    window.onload = function () {
        var myDebounce = document.getElementById("debounce");
        myDebounce.addEventListener("click", debounce(sayDebounce));
    }
</script>
</body>

完整的节流用例

<body>
    <button id="throttle">点我节流!</button>
<script>
    // 节流
    function throttle(fn, wait = 500) {
        let timer = null
        return function (...args) {
            if (!timer) {
                timer = setTimeout(() => {
                    fn.apply(this, args);
                    timer = null;
                }, wait);
            }
        }
    }
    function sayThrottle() {
      console.log("节流成功!");
    }
    window.onload = function () {
        var myThrottle = document.getElementById("throttle");
        myThrottle.addEventListener("click", throttle(sayThrottle));
    }
</script>
</body>
上一篇 下一篇

猜你喜欢

热点阅读