函数节流与防抖
在最近的面试中,有被问到这个问题,当时没有反应过来,整理一下,供大家参考
函数防抖
函数防抖,就是指触发事件后在一定时间内函数只能执行一次,如果在这段时间内再次触发,则会重新计时,直到事件触发后一定时间内不再触发
简单来说,就是在连续多次的触发事件时,只会执行最后一次
因此,实现函数防抖的关键在于判断一定时间内事件是否触发
实现代码
这一部分是用来测试的盒子以及事件触发的回调函数
var box = document.querySelector('.box');
function test() {
console.log('按了');
}
box.onclick = debounce(test,1000);//绑定一个点击事件,延时1000ms
在解释代码之前先讲一下清除计时器
我一开始以为清除计时器用null和用clear一样,其实不然
所有的计时器都会有一个返回值,这个返回值就是计时器的唯一标识
当我们将定时器名赋予null
时,其实只是将计时器的返回值改为了null而已,定时器还是依旧存在的,我们可以做一下的测试代码
function fn () {
var timer = setInterval(function () {
console.log('我是定时器');
timer = null;
console.log(timer);
}, 1000);
}
fn();//我是定时器 /n null
fn();//我是定时器 /n null
很显然,不管调用几次,定时器依旧存在,只是返回值变成了null
因此我们在实现函数防抖不要以为
t = null
已经清除了定时器,所以我们在防抖函数中,要用clearTimeout
清除定时器
function debounce(fn,delay) {
var t = null;
return function() {
if(t) {
clearTimeout(t);
}
t = setTimeout(function(){
fn.apply(this,arguments);
},delay)
}
}
为了封装一个函数,要尽量的避免污染全局变量,因此采用了闭包,将t
作为function
的私有变量,不污染全局变量
最后一个问题
为什么要用
apply
呢?
return
以及函数它的调用者都是window,所以这里不存在this
指向的问题,但当我们需要传入参数数组时,而这个参数个数又不确定,我们只能用argument
来接受不确定个数的参数,因为fn
接受的是单一的参数,而不是数组,因此我们采用apply
来接受这个数组
函数节流
函数节流是限制一个函数在一定时间内只能执行一次
有了函数防抖的基础,节流操作就简单很多了
实现函数节流的主要是要计算每次触发事件的时间差,如果两次触发事件的时间差大于设定的时间,则直接执行,如果小于,则等待执行。
实现代码
我相信初学者一定和我一样有很多的小问号
function throttle(fn,delay) {
var t = null;
begin = new Date().getTime();
return function() {
cur = new Date().getTime();
clearTimeout(t);
if(cur - begin >= delay) {
fn.apply(this,arguments);
begin = cur;
}else {
t = setTimeout(function(){
fn.apply(this,arguments);
},delay)
}
}
}
这个函数是怎么的一个流程呢?
首先当用户点击时,会获取当前的时间戳,也就是点击的时刻,begin
作为初始的时间与cur
做比较,也就是当前点击的时间距离上次点击时间大于delay
会立即执行,如果小于delay
就会创建一个定时器,经过delay
秒后再执行
如果再这个
delay
的时间内疯狂点击会发生什么呢?
很显然当前的时间戳也就是cur
会不断的随时间变大,当时间差大于了delay
就会满足if
的条件,直接执行
也就是说,当我们连续点击时,只有当我们停下前的那一次点击事件会通过else
里的函数输出,其余的都会从满足if
条件的输出!
下次面试时被提问到一定会答出来!