应用场景
我们经常需要监听滚动条滚动或者鼠标的移动,但是浏览器触发这类事件的频率非常高,可能10几毫秒就触发一次,有的时候我们只需要处理函数执行一次,比如文本输入验证,执行多次处理函数反而没必要。
常规实现,以监听 scroll 事件为例
window.onscroll = function () {
//滚动条位置
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
解决方法:
减少DOM操作的频度,也就是稀疏处理函数的执行频率,解决方法就是函数防抖以及函数分流。函数防抖表示只执行一次处理函数,函数分流指降低处理函数的执行频率。
函数防抖
指触发事件后的n秒内函数只执行一次,如果在n秒内又触发了事件,就清除上一次的定时器,重新定时。
简单来说,就是当一个动作连续触发时,只执行最后一次。
简单实现的例子:
window.onscroll=function(){ if(timer){ clearTimeout(timer); } timer=setTimeout(function(){ let scrollTop=document.body.scrollTop||document.documentElement.scrollTop; console.log('滚动位置:'+scrollTop); timer=undefined; },200); }
这里有一个保存timer的技巧,如果不保存timer,那么执行完事件处理函数,timer将被销毁,我们也就无法再清除定时器了,所以要保存这个变量,即使他所在的函数作用域对应的函数已经执行完了。
防抖函数的封装使用 闭包
//封装方法之闭包 //闭包:如果想让一个函数执行完,函数内的某个变量(timer)仍然保留。就可以用闭包 function debounce(method,delay){ var timer=null; return function(){ var that=this; var args=arguments; clearTimeout(timer); timer=setTimeout(function(){ method.apply(that,args); },delay); } } window.onscroll=debounce(function(){ var scrollTop=document.body.scrollTop||document.documentElement.scrollTop; console.log(scrollTop); },200);
应用场景:
(1)搜索框输入。只需用户最后一次输入完,在发送请求;
(2)手机号、邮箱验证输入检测;
(3)窗口大小Resize。只需窗口调整完成后,计算窗口大小,防止重复渲染。
不适用:做图片懒加载时,需要通过滚动位置实时显示图片时,如果使用防抖函数,懒加载函数就会不断被延迟,只有停下来的时候才会被执行,防抖函数对于这种需要实时触发事件的情况就显得不是很友好了。
节流函数
触发事件函数后,短时间内无法连续调用,只有上一次函数执行后,过了规定的时间间隔,才能进行下一次的函数调用。
原理:对处理函数进行延时操作,若设定的延时到来之前,再次触发事件,则清除上一次的延时操作定时器,重新定时。
简单实现的例子:
var startTime=Date.now();//开始时间 var time=500;//间隔时间 var timer; window.onscroll=function throttle(){ var currentTime=Date.now(); if(currentTime-startTime>=time){ var scrollTop=document.body.scrollTop||document.documentElement.scrollTop; console.log('滚动位置:'+scrollTop); startTime=currentTime; } else{ clearTimeout(timer); timer=setTimeout(function(){ throttle(); },50); } }
节流函数的封装使用 闭包
/** * 函数节流throttle * @param method事件触发的操作 * @param delay延迟执行函数的时间 * @param mustRunDelay超过多长时间必须执行一次函数
* 函数间隔delay执行一次,mustRunTime内必须执行依次,因为有可能delay秒内使劲执行函数,这是定时器timer就会不断被清除,就会导致事件永远不会被执行。 */ function throttle(method,delay,mustRunDelay){ var timer=null;//计时器var startTime=0;//开始时间 var currentTime=0;//当前时间 return function(){ var that=this;
var arg=arguments; currentTime=Date.now(); if(!startTime){ startTime=currentTime; } if(currentTime-startTime>=mustRunDelay){ method.apply(that,args); startTime=currentTime; } else{ clearTimeout(timer); timer=setTimeout(function(){ method.apply(that,args) },delay); } } } window.onscroll=throttle(function(){ var scrollTop=document.body.scrollTop||document.documentElement.scrollTop; console.log(scrollTop); },50,500);
应用场景:
(1)滚动加载,加载更多或滚动到底部监听;
(2)高频点击提交,表单重复提交 。
函数防抖与函数分流的思想都是通过设置定时器降低函数的执行频率。
区别:
(1)函数防抖在一段连续的操作结束后,处理回调函数,利用setTimeout和clearTimeout实现;
函数节流在一段连续的操作中,每一段时间只执行一次。
(2)函数防抖关注一定时间连续触发,只在最后执行一次,而函数节流侧重于一段时间内只执行一次。