防抖和节流

132 阅读3分钟

防抖函数(debounce)

定义:当持续触发事件,一定时间内没有触发事件,事件处理函数才会执行一次,如果在设定的时间到来之前,又一次触发了事件,就重新开始计时。

案列

我们通过一个简单案例来一步步实现,当我们在输入框时,我们需要在控制台打印输入的值,这个需求很简单:

let input =document.querySelector('input')
input.addEventListener("keyup",function (e) {
    console.log(e.target.value); 
})

执行后我们发现,控制台会将我们每次输入的值都打印出来,然而实际上我们不需要如此高频的打印,此时我们需要输入完成,且不在输入,并且在1秒后将输入的值打印出来,首先我们来实现第一步,1秒后在打印结果,那么我们自然就想到了定时器

function debounce(delay,value) {
     setTimeout(function() {
        console.log(value); 
     }, delay);
}
input.addEventListener("keyup",function (e) {
    debounce(1000,e.target.value)
})

然而执行完上述函数,我们发现该方法只是在延迟一秒后,将我们每次输入的值都打印了出来,这样完全不符合我们的预期,这时我们就想到,如果我们每次输入时,将上次的定时器清除不就好了,这样第二次输入时,第一次的值就不会被打印出来,所以我们可以这样写

 function debounce(delay,value) {
      let timer
      clearTimeout(timer)
      timer=setTimeout(function() {
         console.log(value); 
      }, delay);
}

想到这里,我们就离成功不远了,执行后我们发现,结果还是和上次一样,这是为什么,是因为我们每次触发‘keyup’事件时都会执行一次函数,函数里的timer每次都是undefined,这样定时器自然就没被清除,如何解决呢,我们可以将timer变量储存在内存中,这样下次执行这个函数时,timer的值就不会为undefined,将局部变量储存在内存中,那么我们自然就想到了闭包

 let input = document.querySelector('#input')
    //  防抖函数
    function debounce(delay) {
        let timer
        return function (value) {
            cleanTimeout(timer)
            timer = setTimeout(function () {
                console.log(value);
            }, delay);
    }

}
 let debounceFc = debounce(1000)
 input.addEventListener("keyup", function (e) {
     debounceFc( e.target.value)
 })

这样一个基本的防抖函数就实现了

节流函数(throttle)

定义:当持续触发事件时,保证一段时间内,只调用一次事件处理函数,也就是一段时间只做一件事情

案例

场景:当我们多次点击按钮时,不论点击多少次,只希望在1秒内它只在控制台内打印一次 首先实现点击按钮,1秒后打印事件

let btn = document.querySelector('button')
function throttle() {
   setTimeout(() => {
       console.log('click');
   }, 1000);
}
btn.onclick = throttle()

执行完发现结果是点击多少次打印多少次,那么我们如果给当前事件加入一个状态呢,只有当不是工作状态时,才执行函数

 function throttle() {
    let flag 
    if (!flag) {
        flag=setTimeout(() => {
            console.log('click');
        }, 1000);
    }
}

点击按钮发现效果和上次一样,原因是我们每点击一次,都会进入‘throttle’函数内,此时的flag都为‘false’,到了这里我们肯定想到了,将flag变量储存在内存中,只有满足条件时,才会执行,那么我们此时就可以用到了闭包 一个基本的节流函数就完成了

let btn = document.querySelector('button')
function throttle() {
    let flag
    return function () {
        if (!flag) {
           flag=setTimeout(() => {
                console.log('click');
                flag=null
            }, 2000);
        }
    }
}
btn.onclick = throttle()