首先自己理解的概念:
防抖函数:防抖按照我的理解就是不管你触发多少次,都等到你最后触发后过一段你指定的时间才触发。
节流函数:节流就是,不管怎么触发,都是按照指定的间隔来执行。
实例:
防抖函数例子:
基础版本:
现在有个要求就是刚开始的时候也触发,最后一次也触发,并且可以配置,先写个测试页面方便测试功能,每次按空格键就会让数字加1,来测试防抖和节流函数。
通过 leading 和 trailing 两个参数来决定开始和结束是否执行,如果 leading 为 true,则没次按空格都会执行一次,如果 trailing 为 true,则每次结束都会将最后一次触发执行。以防抖函数距离,如果两者都为 true,则第一次按空格会加 1,然后快速按空格,此时里面的 getUserAction 并不会执行,而是等到松手后再执行,加入 trailing 为 false,则松手后不会执行。
解释一下,每次记录上次调用的时间,与现在的时间对比,小于间隔的话,第一次执行后之后就不会执行,大于间隔或在间隔时间后调用了,则重置 flag,可以与上面那个基本版的对比着看。
函数防抖的应用场景,最常见的就是用户注册时候的手机号码验证和邮箱验证了。只有等用户输入完毕后,前端才需要检查格式是否正确,如果不正确,再弹出提示语。以下还是以页面元素滚动监听的例子,来进行解析:
// 函数防抖
var timer = false;
document.getElementById("debounce").onscroll = function(){
clearTimeout(timer); // 清除未执行的代码,重置回初始化状态
timer = setTimeout(function(){
console.log("函数防抖");
}, 300);
};
函数防抖的要点,也是需要一个setTimeout
来辅助实现。延迟执行需要跑的代码。
如果方法多次触发,则把上次记录的延迟执行代码用clearTimeout
清掉,重新开始。
如果计时完毕,没有方法进来访问触发,则执行代码。
这个方法的作用是监听ID为
debounce
元素的滚动事件
进入滚动事件方法体的时候,做的第一件事就是清除上次未执行的setTimeout
。而setTimeout
的引用id由变量timer
记录。
clearTimeout
方法,允许传入无效的值。所以这里直接执行clearTimeout
即可。
然后,将需要执行的代码放入setTimeout
中,再返回setTimeout
引用给timer缓存。
如果倒计时300ms
以后,还没有新的方法触发滚动事件,则执行setTimeout
中的代码。
函数防抖的实现重点,就是巧用setTimeout
做缓存池,而且可以轻易地清除待执行的代码。
其实,用队列的方式也可以做到这种效果。这里就不深入了。
函数防抖:注册时邮箱的输入框,随着用户的输入,实时判断邮箱格式是否正确。此时,每一次的用户输入都触发邮箱格式检测事件,造成了浪费,于是设置两次输入之间的时间间隔大于800ms时(用户结束输入时),再执行检查邮箱格式。
假如只过了100ms,上次的定时还没执行,此时清除定时,重新定时800ms。
紧跟着又来了一次输入,上次定时依然没执行,再次清除定时,重新定时800ms。
...
直到最近一次的输入,后面没有紧邻的输入了,这最近一次的输入定时计时结束,终于执行了检查代码。
结果是:如果两次输入触发事件的时间间隔不足800ms的,不执行检查代码。 两次触发事件的时间间隔大于800ms了,则前面的执行检查。
这就是传说中的 函数防抖。
节流就是,不管怎么触发,都是按照指定的间隔来执行,同样给个基本版。
同样和防抖函数一样加上两个参数,也可使用上面的例子来测试,其实两者的代码很类似。
函数节流:一个加载新闻的列表页,只要滚动到页面的最下面就继续加载一部分新闻出来,即滚动加载。这时,就要监听滚动事件,判断若滚动
到页面底部了,就执行加载新闻的代码。
于是设置一个开关,一次只能有一个触发执行,并对执行设置计时一段时间再执行,执行完毕之后再解锁。这就是函数节流。
函数节流应用的实际场景,多数在监听页面元素滚动事件的时候会用到。因为滚动事件,是一个高频触发的事件。以下是监听页面元素滚动的示例代码:
// 函数节流
var canRun = true;
document.getElementById("throttle").onscroll = function(){
if(!canRun){
// 判断是否已空闲,如果在执行中,则直接return
return;
}
canRun = false;
setTimeout(function(){
console.log("函数节流");
canRun = true;
}, 300);
};
函数节流的要点是,声明一个变量当标志位,记录当前代码是否在执行。
如果空闲,则可以正常触发方法执行。
如果代码正在执行,则取消这次方法执行,直接return
。
这个方法的作用是监听ID为
throttle
元素的滚动事件。
当canRun
为true
,则代表现在的滚动处理事件是空闲的,可以使用。
通过关卡if(!canRun)
,等于就拿到了通行证。然后下一步的操作就是立马将关卡关上canRun=false
。这样,其他请求执行滚动事件的方法,就被挡回去了。
接着用setTimeout
规定最小的时间间隔300,接着再执行setTimeout
方法体里面的内容。
最后,等setTimeout
里面的方法都执行完毕,才释放关卡canRun=true
,允许下一个访问者进来。
这个函数节流的实现形式,需要注意的是执行的间隔时间是>=300ms
。如果具体执行的方法是包含callback
的,也可以将canRun=true
这一步放到callback
中。理解了函数节流的关卡设置重点,其实改起来就简单多了。
demo地址:https://wall-wxk.github.io/blogDemo/2017/02/15/throttleAndDebounce.html