问题
常见的问题就是函数的高频次调用,会极度消耗性能,严重的会把浏览器拖垮,卡死,最常见的是浏览器的窗口大小变化,输入框查询数据库,所以我们有必要限制函数的调用频次,同时确保他不影响用户体验。
解决
函数节流(throttle)与函数防抖(debounce)都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。
函数防抖(debounce)是函数先执行,等待n毫秒后,再执行,如果在等待这n毫秒期间,又调用此方法,就会打断,重新计算(也就是重新等待n毫秒)后执行;就像坐电梯一样,有人在一定的时间内按了就重新等待设置的时间,等没有人在上的时候才执行。
函数节流(throttle)是我先设定一个等待周期,等待周期结束后执行函数,中间不受影响,执行完函数后,进入下一个等待周期;就像地铁一样,每站等待3分钟,3分后,开车,进入下一站。
防抖函数和节流函数的应用场景:
1.window对象的resize、scroll事件
2.拖拽时的mousemove事件
3.文字输入、自动完成的keyup事件
实现
函数防抖(为了防止他一直触发,我们制定一个时间限制time,让它的执行时间间隔大于时间限制就主动执行)
/**
* fn执行函数
* wait 函数执行等待时间(电梯从开门到关门的设定时间)
* time 函数时间间隔(限制电梯从开门到关门的实际时间,防止他一直触发不会执行。)
*
*/
function _debounce(fn,wait,time){
var previous=null;//记录上一次运行的时间
var timer=null;
return function(){
var = +new Date();//记录当前时间
if(!previous) previous = now;
//当上一次执行的时间与当前的时间差大于设置的执行间隙时长的话,就主动执行一次
if(now -previous > time){
clearTimeout(timer);
fn();
previous = now;//执行函数后,马上记录当前时间
}else{
clearTimeout(timer);
timer = setTimeout(function(){
fn();
},wait);
}
}
}
function _log(){
console.log(1);
}
window.onscroll = _debounce(_log,500,2000)
函数节流(每隔time执行一次函数,在time未执行完的时,函数不执行,直接返回;)
/**
* 函数节流
* fn 执行函数
* time 函数执行指定时间间隔
*/
function _throttle(fn,time){
let _self=fn,
time,
firstTime=true;//记录是否是第一次执行的flag
return function(){
let args= arguments,//解决闭包传参问题
_me=this//解决上下文丢失问题
if(firstTime){//若是第一次,则直接执行
_self.apply(_me,args)
return firstTime = false
}
if(timer){//定时器存在,说明有事件监听器在执行,直接返回
return false
}
timer =setTimeout(function(){
clearTimeout(timer)
timer= null
_self.apply(_me,args)
},time || 500)
}
}
function _log(){
console.log(1);
}
window.onscroll = _throttle(_log,500,2000)
我自己的理解
节流节流的概念就是这样子的,比如你在那个input框输入数字,输入一个查询条件吧,然后这个条件会实时传入后端,就是说实时监听,只要input框的数值发生变化的时候,他就会去后端去请求。那么问题来了,你如果写数字的话,123456789。你从一输入到九,这块儿是不是要变化九次,那么每变化一次,都会去后台请求数据。但对性能来说,你已经请求了9次,但你正常,你只需要拿到最后一条数据,就行了。那么你请求九次,那其他的8次其实都是多余的,这就是节流的概念,节流的概念就是去除那些不要的,比如最简单的理解,就是做个延迟。
防抖比如说你在改变div宽高的时候,他就会去执行一个函数,当你拖动那个浏览器大小的时候,那个div的宽高会不停地会发生变化,而且那个数值会很快,他就会一直在去执行这个函数。然后你需要的只是他停下来的那一瞬间去执行。所以说这也可以加延迟,就是节流防抖,不外乎就是一个概念:等,等一会儿不操作,或者是稍微卡的一段时间,就是0.5秒这样子。其实。从那个人的体验角度来说,并没有停顿很长时间,但是从性能角度来说,已经被服务器省下了很多的那个处理空间。