JS防抖与节流

如我们有个需求:在窗口大小改变后,计算窗口的宽高比。

可能代码如下:

function calc() {
    console.log(window.innerWidth / window.innerHeight)
}

window.addEventListener('resize', calc)

这可以满足需求,但是当我们拉动窗口大小时发现,控制台的输出频率非常高,造成不必要的消耗。实际上我们只需要在拖动窗口结束时计算一次就可以。

所以要根据需求,做防抖或节流来优化实现。


一、防抖

1.1 什么是防抖

如果短时间内大量触发同一事件,只会执行一次函数。

1.2 实现

function debounce(fn,delay){
    let timer = null //借助闭包
    return function() {        
        if(timer){
            clearTimeout(timer) //进入该分支语句,说明当前正在一个计时过程中,并且又触发了相同事件。所以要取消当前的计时,重新开始计时
        }
        timer = setTimeout(fn,delay) // 进入该分支说明当前并没有在计时,那么就开始一个计时
    }
}

那我们上面的需求代码就可以改为

function calc() {
    console.log(window.innerWidth / window.innerHeight)
}

function debounce(fn,delay){
    let timer = null
    return function() {        
        if(timer){
            clearTimeout(timer)
        }
        timer = setTimeout(fn,delay)
    }
}

window.addEventListener('resize', debounce(calc, 300))

那如果在改变窗口大小的过程中,就希望开始计算呢?这就要用节流

二、节流

2.1 什么是节流

如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效

2.2 实现

function throttle(fn,delay){
    let valid = true
    return function() {
       if(!valid){
           //休息时间 暂不接客
           return false 
       }
       // 工作时间,执行函数并且在间隔期内把状态位设为无效
        valid = false
        setTimeout(() => {
            fn()
            valid = true;
        }, delay)
    }
}

那我们上面的需求代码就可以改为

function calc() {
    console.log(window.innerWidth / window.innerHeight)
}

function throttle(fn,delay){
    let valid = true
    return function() {
       if(!valid){
           //休息时间 暂不接客
           return false 
       }
       // 工作时间,执行函数并且在间隔期内把状态位设为无效
        valid = false
        setTimeout(() => {
            fn()
            valid = true;
        }, delay)
    }
}

window.addEventListener('resize', throttle(calc, 300))


三、更多的应用场景与总结

如:滚动条高度获取,提交按钮的连续点击造成重复提交,输入框内值变化时事件的响应等

本文只以最简单实现,用来快速学习防抖与节流的实现思路,代码不健全不建议直接使用。


参考资料: https://segmentfault.com/a/1190000018428170


2021-11-16 17:01:36 757 0

参与讨论

选择你的头像