1. 简单用法,在函数体中直接写入
由于有些业务场景使用防抖节流封装成函数后,会出现函数嵌套这种令人恶心的代码,让人头皮发麻, 比如:一个保存功能按钮,你的ajax请求函数已经封装过一次,然后在组件中使用时又在外层套了一层函数,最后,在某个按键点击事件上调用时,还得在上面在包一层防抖节流函数。啊!!!!,有没有感觉代码就像加了confrim二次确认弹框
所以我们可以直接利用定时器,在该函数直接写语句代码写一个简单的防抖节流
- 防抖 reactHooks为列
export default function Foo(){
const timer=useRef(null)
//点击保存按钮
const handleClick=()=>{
if(timer.current) clearTimeout(timer.current)// 清除上一次定时器
timer.current=setTimeout(()=>{
/* handleCick函数体内容功能代码
...
...
*/
},500)
}
return (
<div>
<button onClick={handleCLick}>保存</button>
</div>
)
}
由上面的例子可以看出,再次点击按钮,只要上一次的定时器还存在就会清空上一个的定时器(包括里面的逻辑代码),从而新开一个定时器,如果用户在指定时间间隔连续点击,就会一直清空上一个的定时器,直到最后一次点击才触发。
- 节流 reactHooks为例:
export default function Foo(){
const timer=useRef(null)
//点击保存按钮
const handleClick=()=>{
if(timer.current) return
/* handleClick函数体内容功能代码
...
...
*/
timer.current=setTimeout(()=>{
timer.current=null
clearTimeout(lock.current);//执行完毕清除当前计时器
},500)
}
return (
<div>
<button onClick={handleCLick}>保存</button>
</div>
)
}
由上面例子我们可以看出,只需定义一个定时器,他为空时就走下面的逻辑,并且开启定时器,500ms后又自动清空,当不为空时,就会return,终止下面的逻辑,
2. 防抖,节流函数封装
- 防抖
const debounce=(fn,delay= 500)=>{
let timer=null
return function(...args){
//清除上一次的定时器
if(timer) clearTimeout(timer)
timer=setTimeout(()=>{
//箭头函数this指向上一级函数也就是调用者,无需修改this
fn(...args)
},delay)
}
}
//使用
const foo= debounce((a,b,c)=>{
console.log(a,b,c)
})
foo(1,2,3) //1,2,3
- 防抖第一次立即执行 有些时候我们设置的防抖时间过长,用户第一次点击时也会延迟,可是我们并不想在第一次的时候延迟,怎么办呢? 这个时候我们可以增加第三个参数firstClick:Boolean当需要第一次执行时传入
const debounce=(fn,delay=500,firstClick=false)=>{
let timer=null
return function(...args){
if(timer) clearTimeout(timer) //清除上一次的定时器
if(firstClick){
if(!timer){
fn(...args)
}
//再开启定时器结束时赋值为null,防止每次点击都走第一次,不然会失去防抖效果
timer=setTimeout(()=>{
timer=null
},delay)
}else{
timer=setTimeout(()=>{ //形成闭包保存timer
fn(...args)
},delay)
}
}
}
上面的代码修改之后的效果就变成了,用户第一次点击会立即执行,但是在定时器的的延时时间内,连续点击都会没有效果,总而言之就是只有第一次才会触发,后续点击都没效果,(可能有人会说这是节流,不!这不是节流,节流和防抖的本质区别:节流是用户连续点击只要规定的时间一到就会执行一次。而防抖是用户只要在规定的时间连续点击,就算连续点击一天,也只会执行一次)
- 节流
function throttle (fn, delay=500) {
let timer=null
return function (...args) {
if (timer) return
timer = setTimeout(() => {
fn(...args)
timer = null
clearTimeout(lock.current);//执行完毕清除当前计时器
}, delay)
}
}
从上面函数看出,节流函数相对于防抖函数就要简单一点了,直接在规定的时间检查定时器是否存在,存在就不触发,不存在就触发,所以效果就变成了,不管你连续点击多久,在指定时间间隔都会执行一次。