- 防抖和节流用来都是用来控制事件的触发的次数,减少触发频率提升网站性能。
防抖
- 防抖:定义时间t,在t时间后执行函数,在t时间内如果事件重复触发,则重新计时
- 立即执行和非立即执行:在事件触发时先执行函数再开始计时;先开始计时,时间到了再执行函数
综合以上两点实现防抖函数:
传入三个参数:
func:需要防抖的函数
delay:防抖的时间
immediate:是否立即执行,这里默认为立即执行
使用了在ts项目中的例子:
export default function debounce(func:Function,delay=100,immediate=true){
let timer:NodeJS.Timeout|null;
return function(this:any,...args:Array<any>){
const context = this;
//防抖函数的关键,在timer还存在时如果触发了事件,则清空定时器,重新计时
if(timer) clearTimeout(timer);
//判断是否需要立即执行
if(immediate){
if(!timer) func.apply(context,args);
timer = setTimeout(()=>{
timer = null;
},delay)
}else{
timer = setTimeout(() => {
func.apply(context,args)
}, delay);
}
}
}
节流
- 节流:定义一个时间t,在t时间内只允许触发一次事件
- 首节流和尾节流:事件触发时是否立即执行,与防抖中的immediate类似
基于时间戳的首节流函数:
function throttle(fn,delay=1000){
let preTime = 0;
return function(...args){
let now = new Date();
let context = this;
let res;
if(now-preTime>=delay){
res = fn.call(context,...args);
preTime = new Date();
}
return res
}
}
基于计时器的尾节流:
// 定时器 尾节流
function throttle2(fn,delay=1000){
// timeout一定要放在外面,否则每次运行都会创建一个timeout。
let timeout = null;
return function(...args){
let context = this;
let res;
if(!timeout){
timeout = setTimeout(()=>{
res = fn.call(context,...args);
timeout = null;
},delay)
}
return res;
}
}
结合前二者的首尾节流:
首尾节流可以实现当事件触发时立即执行,事件最后一次触发后延迟一段时间执行
function throttle3(fn,delay=1000){
let timeout = null;
let preTime = 0;
return function(...args){
let context = this;
let remain = 0;
let now = new Date();
let res;
clearTimeout(timeout);
remain = delay - (now-preTime);
//如果remain小于0则进行首节流
if(remain<=0){
res = fn.call(context,...args);
preTime = new Date();
}else{
timeout = setTimeout(()=>{
res = fn.apply(context,args);
},delay)
}
return res;
}
}
防抖和节流的区别与用途
区别:
- 体现在运行机制的区别:
- 防抖中一个事件在t时间内重复触发,计数器会重新计时
- 节流事件在t时间内触发时不会重新计时,而是选择不予理会
- 体现在用途上的区别:
- 节流函数体现的是减少触发次数,而不是让触发次数保持为1次,如鼠标移动、窗口变换、元素拖拽等事件,需要减少对这些事件的响应次数减少资源浪费,但是不能只响应一次
- 防抖则体现的是一种"等待"的效果,如输入验证、动态搜索、文本翻译等,需要"等待"用户把该输入的输入完成了再执行,如果用户在t时间内没有输入完成,则判断为需要继续等待用户,所以重新计时