我们先抛开概念不谈,其实在生活中也有很多防抖的例子:
这其实这就是防抖的基本概念了~说白了就是在一段时间只执行一次,也就是我们上面的电脑只打开这一次。
我们上面的使用电脑可以理解为触发事件
,而与我上面标注的setTimeout
和clearTimeout
其实就是防抖的主要要素了。
当然上面的是生活中的例子,那我们在我们的日常开发中其实也经常用到,比如我们调整页面的大小,验证表单某个字段是否重复时发生请求次数控制,防止表单多次提交等。
说了这么多,相信大家大概理解了防抖的概念,那我们现在来实现一个防抖吧,假设我们要点击一个按钮新增一条信息,当然我们不希望每次点击都调用接口新增,我们希望多次点击只新增一次,这时候我们该怎么写呢?
首先我们先简单的模拟一个按钮被点击的过程。
// debounce.js let addBtn=document.getElementById('add') function addOne(){ console.log('增加一个') } addBtn.addEventListener('click',addOne)
因为我们需要对执行的事件进行处理所以接下来我们需要封装一下addOne
函数。
// debounce.js let addBtn=document.getElementById('add') function addOne(){ console.log('增加一个') } function debounce(fun){ return function(){ fun() } } addBtn.addEventListener('click',debounce(addOne))
上面我们用闭包处理了一下addOne
函数,接下来我们需要添加一个延时器setTimeout
来倒计时,当我们点击按钮后过2s
再执行。
// debounce.js function debounce(fun,time){ return function(){ setTimeout(()=>{ fun() },time) } } addBtn.addEventListener('click',debounce(addOne,2000))
现在延时的目的是达到了但是每次点击都会新增一个新的setTimeout
而且并不能达到我们多次点击只执行一次的效果。
这时候就需要clearTimeout
登场了,我们需要在我们点击了按钮后也就是debounce
执行时要先把之前的setTimeout
先清除再重新计时。
function debounce(fun,time){ let timer return function(){ clearTimeout(timer) timer=setTimeout(()=>{ fun() },time) } }
现在我们的一个防抖功能就完成了,但是这还没完,如果我们在addOne()
打印this
会发现我们这样执行的this
是指向Window
的。
这当然不是我们所希望的,我们需要使用apply
来改变this
指向,再者就是我们需要考虑到执行函数的参数,因为不同的函数肯定会有不同的参数传入,对于参数我们可以使用arguments
处理。
function debounce(fun,time){ let timer return function(){ clearTimeout(timer) let args = arguments timer=setTimeout(()=>{ fun.apply(this,args) },time) } }
这样我们的防抖函数就手写完成了,看起来其实也并不难。
总而言之防抖就是在不断的操作中(输入、点击等)最终只执行一次的一种提高性能的方法。
当然我们生活中也会有很多节流的的例子,不知道大家有没有留意过公园的洒水机:
30min
30min
的时候一直保持静止状态30min
则会触发洒水的事件30min
和当前时间,这两个就是节流的主要要素了。说了这么多,相信大家大概理解了节流的概念,那我们现在来实现一个节流吧,假设我们现在要实现一个鼠标滚动打印事件,想让它在3s执行一次,这时候我们该怎么写呢?
首先我们先模拟一个触发事件。
// throttle.js function scrollTest(){ console.log('现在我触发了') } document.addEventListener('scroll',scrollTest)
接下来我们封装一个节流函数,跟防抖一样我们也需要利用闭包,顺便再加一个参数接收节流时间。
// throttle.js ... function throttle(fun,time){ return function(){ fun() } } document.addEventListener('scroll',throttle(scrollTest,3000))
因为我们的节流是在一段时间内执行一次也就是说如果两次鼠标滚动的时间间隔未到所设置的时间则不执行。
那我们可以记录一下每次滚动的时间戳来进行对比。
// throttle.js ... function throttle(fun,time){ let t1=0 //初始时间 return function(){ let t2=new Date() //当前时间 if(t2-t1>time){ fun() t1=t2 } } }
我们会记录两个时间一个是t1
代表初始时间一个是t2
代表当前时间,如果当前时间距离上一个时间也就是初始时间大于所设置的time
。
那我们就可以执行fun()
并且把初始时间变更为这一次执行的时间,这样每次我们执行过后t1
就变成了上一次执行的时间。
这样我们的一个节流功能就完成了。
// throttle.js ... function throttle(fun,time){ let t1=0 //初始时间 return function(){ let t2=new Date() //当前时间 if(t2-t1>time){ fun() t1=t2 } } }
当然我们也需要像防抖一样改变this
指向和接收参数,最后完成后是这样的。
// throttle.js ... function throttle(fun,time){ let t1=0 //初始时间 return function(){ let t2=new Date() //当前时间 if(t2-t1>time){ fun.apply(this,arguments) t1=t2 } } }
至此一个节流函数就手写完成了,是不是也不会很难呢?
总而言之节流就是在一段时间内不断操作而在你规定的时间内只执行一次的一种提高性能的方法