当resize,onScroll,或者一些表单change的事件频繁触发的时候,会频繁调用相应的事件处理函数,这很影响浏览器的执行效率,也影响到用户的体验。所以当一些事件会高频率发生的时候,可以采用防抖和节流两种方式进行处理。
节流
原理:一段时间内只允许一个事件发生,也就是当前事件必须与前一个事件间隔大于delay的事件,当前的事件才会执行
节流主要有时间戳和计时器两种实现方式:
时间戳实现节流:
这种实现方式,当第一次触发事件的时候,事件处理函数一定会被调用,最后一次可能会被调用也可能不会被调用。
function throttle(fn,delay){
var preTime=new Date();
return function(...args){
var refThis=this;
var nowTime=new Date();
if(nowTime-preTime>delay){
fn.apply(refThis,args);
preTime=new Date();
}
}
}
function fn(){
console.log("触发函数节流")
}
window.addEventListener("resize",throttle(fn,1000))
计时器实现节流:
这种第一次触发事件会等到delay事件之后才会执行,最后一次可能会也可能不会被触发。
function throttle(fn,delay){
var timer=null;
return function(..args){
var refThis=this;
if(!timer){
timer=setTimeout(function(){
fn.apply(refThis,args);
timer=null;
},delay)
}
}
}
function fn(){
console.log("触发函数节流")
}
window.addEventListener("resize",throttle(fn,1000))
节流还可以采用时间戳和计时器结合的方法。
防抖
原理:只有当delay时间段内没有事件发生,才会触发事件,每次事件发生的时候,如果delay时间内有触发则会重新记时。
无论与之前的事件执行有没有间隔大于delay,都要clear掉事件执行器,如果小于,这时候之前的setTimeout计时器还没有执行,要清除之前的定时器。如果大于,之前的定时器已经执行,这时候清除也没有什么影响,所以最好的做法是,当事件触发的时候,清除掉之前的定时器,然后定义一个新的延时定时器
function debounce(fn,delay){
var timeout;
return function(){
var refThis=this;
var arg=arguments;
if(timeout){
clearTimeout(timeout);
}
timeout=setTimeout(function(){
fn.apply(refThis,arg);
},delay)
}
}
function fn(){
console.log("触发函数防抖")
}
window.addEventListener("resize",debounce(fn,1000))