防抖
原理: 其总是在设置时间的最后一刻执行一次,且只执行一次。在事件被触发n秒后再执行回调函数,如果在这n秒内又被触发,则重新计时。
整个防抖实现的流程大概是:
1.点击执行函数
2.清除定时 clearTimeout(timer),需要清除上一次的定时器重新计时
3.设置定时 setTimeout
(1)若在规定时间内又有点击事件,那就要重新返回到清除定时的操作,然后再次设置定时
(2)如果在规定时间内没有点击事件,就执行函数中相应的任务(如:提交表单)
// 防抖 用户多次操作已最后一次为准
export const debounce = ( fn: Function , delay: number = 300 ): any => {
let timer: any = null;
return (...args: any ) => {
console.log(timer);
if ( timer ) {clearTimeout(timer)}
timer = setTimeout ( () => {
fn.apply(this,args);
},delay)
}
}
节流
应用场景:
考虑用户滚动鼠标触发事件的场景:假设页面在监视用户滚动页面的行为来做出响应的反映,如果此时用户不断地滚动页面,就会不断地产生请求,响应也会不断增加,这样既浪费资源还容易导致网络中阻塞。那我们可以在触发事件的时候立刻执行任务,然后设定时间间隔限制,在本段时间间隔内无论用户怎么滚动页面都将忽视操作,在时间到了之后,如果监测到用户有滚动行为,再次像之前所说的那样执行任务和设置时间间隔。
原理: 如果在同一个单位时间内某事件被触发多次,只有一次能生效。在密集调用时,节流方法相当于每隔一段时间触发一次。
总体来说的整个流程就是:
1.触发事件
2.执行任务
3、设置时间间隔
// 节流 适用于密集调用的时候,每隔一段时间来执行一次
export const throttle = ( fn: Function ,delay: number =300 ): any => {
let time:any; //不用赋值
return (...args: any) => {
if ( !time ) {
time = setTimeout ( () => {
fn.apply( this, args);
time = null;
},delay)
}
}
}
核心逻辑:
判断触发的事件是否在时间间隔内,如果在事件间隔内,就不触发事件,如果不在事件间隔内,我们就触发事件,简单来说如果 timer 被赋值了,也就是任务还在等待执行,此时就不触发事件,如果timer没有被赋值,就给他赋值触发事件。
clearTimeout(timer) 和 timer = null 的区别
1.timer=null 的时候,只是改变了 timer 的指向,并没有清除掉定时器,定时器依旧可以使用。此时定时器在内存中虽然没有变量指向它,但它仍存在内存中,在防抖函数中,如果fn函数使用timer=null ,那当fn经过防抖函数限制后,在delay时间内调用多少次fn函数,就会有多少次的定时器存在内存中,就会执行多少次fn函数,并不能实现预期中的在delay时间内只执行一次fn函数。
2.clearTimeout(timer):是在内存中清除掉定时器,所以在防抖函数中,在delay时间内,无论执行fn多少次,都只会有一个定时器存在。timer会分配一个随机数字id,clearTimeout后,timer的变量指向的数字id还在, 只是定时器停止了。