应用场景
我们经常需要监听滚动条滚动或者鼠标的移动,但是浏览器触发这类事件的频率非常高,可能10几毫秒就触发一次,有的时候我们只需要处理函数执行一次,比如文本输入验证,执行多次处理函数反而没必要。
常规实现,以监听 scroll 事件为例
window.onscroll = function () {
//滚动条位置
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
解决方法:
减少DOM操作的频度,也就是稀疏处理函数的执行频率,解决方法就是函数防抖以及函数分流。函数防抖表示只执行一次处理函数,函数分流指降低处理函数的执行频率。
函数防抖
指多次触发事件后,事件处理函数只执行一次,而且是在事件操作停止的时候。具体思路就是延迟处理函数,如果设定的时间到来之前又一次触发了事件,就清除上一次的定时器,重新定时。
简单实现的例子:
window.οnscrοll=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);
适用性:监听滚动条的位置,控制是否显示返回顶部按钮是,就可以将抖动函数应用其中。
不适用:做图片懒加载时,需要通过滚动位置实时显示图片时,如果使用防抖函数,懒加载函数就会不断被延迟,只有停下来的时候才会被执行,防抖函数对于这种需要实时触发事件的情况就显得不是很友好了。
节流函数
触发事件函数后,短时间内无法连续调用,只有上一次函数执行后,过了规定的时间间隔,才能进行下一次的函数调用。
原理:对处理函数进行延时操作,若设定的延时到来之前,再次触发事件,则清除上一次的延时操作定时器,重新定时。
简单实现的例子:
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超过多长时间必须执行一次函数 */ function throttle(method,delay,mustRunDelay){ var timer=null;//计时器 var args=arguments; var startTime=0;//开始时间 var currentTime=0;//当前时间 return function(){ var that=this; 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);
函数防抖与函数分流的思想都是通过设置定时器控制函数的执行频率。