大纲
一、出现缘由
二、什么是防抖debounce和节流throttle
三、应用场景
3.1防抖
3.2节流
一、出现缘由
前端开发中,有一部分用户行为会频繁触发事件,而对于DOM操作,资源加载等耗费性能的处理,很可能导致卡顿,甚至浏览器崩溃,防抖和节流就是为了这一类的问题出现的前端优化技术。
二、什么是防抖debounce和节流throttle
防抖debounce是函数在规定延迟时间内不被调用,才能再次被调用,如果在规定时间内调用,延迟重新开始计算;
节流throttle是在规定的延迟时间间隔后,函数才执行一次,以固定的频率被触发。
三、简单实现
3.1防抖
连续触发事件的时候,不会有任何反应,停止触发事件的多少秒,就会执行,在延迟时间内执行函数,就重新开始一个定时器。
function debounce(func,delay=300,timer=null){return (...args){clearTimeout(timer);timer=setTimeout(func.bind(null,...args,delay);)}
}
function query(){//ajax
}
input.addEventListener('keyup',debounce(query))
3.2节流
触发事件的时候,执行一个函数,在之后的一段时间内进这个函数,会被return,真正的逻辑不能执行,定时器在一定时间后重置开关,再进来就能再次执行真正的逻辑了。
function throttle(func,delay=60){let lock=false;return (...args)=>{if(lock)reutrn;function(..args);lock=true;setTimeout(()=>lock=false,delay);}
}
function query(){//ajax
}
decument.addEventListener('scroll',throttle(query));
四、应用场景
3.1防抖throttle的应用场景
防抖适用于window.onscroll事件,等到拉动动作结束后再触发一个事件,或者拖拽
_.throttle=function(func,wait,options){var context,args,result;var timeout=null;var previous0;if(!options)options={}var later=function(){previous=options.leading===false:0:new Date();timeout=null;result=func.apply(context,args);if(!timeout)context=args=null;}return fucntion(){var now=new Date();if(!previous && option.leading===false)previous=now;var remaining=wait-(now-previous);context=this;args=arguments;if (remaining <= 0 || remaining > wait) {if (timeout) {clearTimeout(timeout);timeout = null;}previous = now;result = func.apply(context, args);if (!timeout) context = args = null;} else if (!timeout && options.trailing !== false) {timeout = setTimeout(later, remaining);}return result;}}
3.2节流throttle的应用场景
下面具体讲一个例子
假设我们网站有一个搜索框,用户输入文本我们自动会联想匹配除一些结果供用户选择,我首先想到的做法是监听keypress事件或change事件,然后ajax请求数据,但是当用户快速输入的时候,就会瞬间触发一连串的请求,这无疑不是我们想要的,我们想要的是用户停止输入的时候才去触发查询的请求,这时候函数防抖可以帮助我们。
_.throttle=function(func,wait,immediate){var timeout,args,context,timestamp,result;var later=function(){ //如果没有超过等待时间,就接着设置一个定时器,时间是delay的时间减去方法执行的时间var last=new Date().getTime() - timestamp;if(last<wait && last>=0){timeout=setTimeout(later,wait-last);}else{ //如果已经过wait时间了,就直接清除定时器,给result赋值clearTimeout(timeout);if(!immediate){result=func.apply(context.args);if(!timeout)context=args=null;}}}return function(){context=this;args=arguments;timestamp=new Date().getTime();var callNow=immediate && timeout; //如果是立即执行或者之前执行过还没过延迟时间if(!timeout)timeout=setTimeout(later,wait); //如果之前没执行过,现在开始定时任务,如果执行过,timeout存在,就返回个空的result.if(callNow){ //如果是立即执行,就立即执行fn,这时候console.log(1);result=func.apply(context,args);context=args=null;}return result;}}function query(){//ajaxconsole.log('ajax');}$("#search").keypress(_.throttle(query,300));