Twlig / issuesBlog

MIT License
3 stars 0 forks source link

防抖和节流 #37

Open Twlig opened 2 years ago

Twlig commented 2 years ago

防抖和节流

  1. 防抖(debounce):触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间

    举例:就好像在百度搜索时,每次输入之后都有联想词弹出,这个控制联想词的方法就不可能是输入框内容一改变就触发的,他一定是当你结束输入一段时间之后才会触发。

  2. 节流(throttle):高频事件触发,但在 n 秒内只会执行一次,所以节流会稀释函数的执行频率

    举例:预定一个函数只有在大于等于执行周期时才执行,周期内调用不执行。就好像你在淘宝抢购某一件限量热卖商品时,你不断点刷新点购买,可是总有一段时间你点上是没有效果,这里就用到了节流,就是怕点的太快导致系统出现bug。

区别:防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。

防抖代码

n秒内只执行最后一次。需要设置一个计时器,n秒才触发。在n秒内如果再次触发则取消上一次的触发。需要取消计时器,就要记录上一次的ID,为了维护全局变量纯净,采用闭包来实现。

function debounce(fn, waitTime) {
    let clearNum = null;
    return function() {
        clearTimeout(clearNum);
        clearNum = setTimeout(()=> {
            fn.apply(this, arguments);  //this指向window对象
        }, waitTime);
    }
}
function sayHi(name) {
    alert("防抖成功!" + name);
}
var fn = debounce(sayHi,3000);
//三秒内运行
fn("amy")
fn("lili")
fn("zzy")
//只有zzy运行

节流代码

n秒内只执行一次。

采用一个n秒的定时器记录是否可以调用函数。有计时器说明距离上一次调用函数时间还在n秒内,不能调用。因此当定时器存在时,不调用函数;当定时器在存在时,调用函数。初始时没有定时器。

function throttle(fn, waitTime) {
    let timeout;
    return function() {
        if(!timeout) {
            fn.apply(this, arguments);
            timeout = setTimeout(() => {
                timeout = null;  //n秒时间到,把定时器置空,下一次可以调用函数
            }, waitTime);
        }
    }
}
function sayHi(name) {
    alert("节流成功!" + name);
}
var fn = debounce(sayHi,3000);
//三秒内运行
fn("amy")
fn("lili")
fn("zzy")
//只有amy运行

使用场景:

如果事件触发是高频但是有停顿时,可以选择debounce; 在事件连续不断高频触发时,只能选择throttling,因为debounce可能会导致动作只被执行一次,界面出现跳跃。

参考文章:
Twlig commented 2 years ago

防抖具体应用示例

<body>
  <div id="container">
    <input type="text" id="debounce">
  </div>
</body>
<script>
    //模拟一个ajax请求
    function ajax(content) {
        console.log('ajax request ' + content)
    }

    function debounce(fun, delay) {
        let clearNum = null
        return function (...args) {
            clearNum && clearTimeout(clearNum)
            let callNow = !clearNum
            clearNum = setTimeout(function () {
                fun(...args)
            }, delay)
            if(callNow) {
                fun(...args)
            }
        }
    }
    let inputb = document.getElementById('debounce')
    let debounceAjax = debounce(ajax, 500)
    inputb.addEventListener('keyup', function (e) {
        debounceAjax(e.target.value)
    })
</script>
Twlig commented 2 years ago

改编防抖实现类似抖音直播连续点赞,间隔一秒后重置效果

    let dom = document.getElementById("btn")
    function debounce(fn, time) {
        let id
        let num = 0
        return function () {
            num = fn(num)
            id && clearTimeout(id)
            id = setTimeout(() => {
                num = 0
            }, time)
        }
    }
    function count(num = 0) {
        num++
        console.log(num)
        return num
    }
    let countDebounce = debounce(count, 1000)
    dom.addEventListener('click', function () {
        countDebounce()
    })