近段时间写项目,图片过多,为了减少浏览器请求负担就用了懒加载,写完懒加载后发现很多地方需要优化,比如单位时间内多次执行scroll函数会不停执行for循环,小项目尚可,大项目中这无疑是一个大负荷,于是去学习了一下防抖和回流
测试例子:以浏览器窗口scroll事件为例打印当前时间
function test(){
let time = new Date();
console.log(`${time.getHours()}:${time.getMinutes()}`)
}
防抖(debounce)
高频触发事件后,函数不会因为事件而多次触发,函数只执行一次,在函数执行之后,方可再次执行,这样在函数可执行阶段又不会因为多次无用的调用而浪费效率
function fn(callback,time){
let timer = null;
return function(){
clearTimeout(timer);
timer = setTimeout(callback,time)
}
}
利用函数的闭包执行判断,因为定时器的异步,单位时间的定时器会进执行栈,最后执行,再次触发函数就会清除定时器,停止触发的时候再执行定时器,反复如此
window.addEventListener("scroll",fn(test,1000))
节流(throttle)
(1)时间戳
function fn(callback,time){
let oldtime = new Date();
return function(){
let newtime = new Date();
if(newtime - oldtime >= time){
callback();
oldtime = new Date();
}
}
}
以两次事件执行的时间差判断,如果大于预计时间那么只执行一次,并且重新赋值之前的时间变量
(2)定时器
function fn(callback,time) {
var timer = null;
return function() {
if (!timer) {
timer = setTimeout(function() {
timer = null;
}, time);
}
}
}
第一次触发事件,到达规定时间再执行这个函数,执行之后马上清除定时器,开始新的循环
优化
节流的以上两种办法都不是最优效果,我们可以把这两个进行合并
function fn(callback,time) {
let timer = null;
let oldtime = new Date();
return function() {
let newtime = new Date();
clearTimeout(timer);
if(newtime - oldtime >= time){
callback();
oldtime = new Date();
}else{
timer = setTimeout(callback,time);
}
}
}
这样就做到了开始一次结束一次
区别
以scroll为例,在高频触发事件,防抖单次事件只会延迟执行一次函数,节流会以时间差多次执行,但是效率会最大化,就像水龙头,防抖是无论你调节水速无论多快,水龙头只会在你不再调节的时侯出水,节流是控制水流的速度,每隔一段时间出水一次
ps:如果怕因为变量的混用可以加上fn.call(this, arguments),如果在定时器使用记得预先定义this
运用
防抖:input输入框,用户以一种究极手速疯狂输入,你想用keydown事件正则验证,这时候用防抖就可以大大的减少事件的请求
节流:图片懒加载,多次请求响应式:网购点击抢购