函数防抖:当某事件被持续触发时,一定时间内事件没有再触发,事件处理函数才会执行一次,如果设定的时间到来之前,又重新触发了一次事件,就重新开始计时延迟。总结为一句话,多次触发事件,在最后一次延迟规定时间后执行。

简单的函数防抖代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function debounce(fn, wait){
let timeout = null;
return function(){
if(timeout !== null)
clearTimeout(timeout);
timeout = setTimeout(fn, wait);
}
}

// handle
function handle(){
console.log(Math.random());
}

//触发事件
window.addEventListener('scroll', debounce(handle, 1000));

我们可以看出,当事件scroll触发后1000ms后,执行handle函数,当滚动事件持续触发时,handle函数是不执行的。

** 案例 **表单输入校验

比如监听输入事件校验邮箱,如果我们每输入一次都要校验邮箱,这就造成了浪费,于是我们可以利用函数防抖,在输入间隔500ms时,进行校验。

1
2
3
4
5
6
7
8
9
10
11
12
const reg = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; 

$('#email').on('keyup', verfiyEmail());

function verifyEmail(){
let timer = null;
return function(){
if(timer !== null)
clearTimeout(timer);
timer = setTimeout(function(){ console.log('执行校验') }, 500)
}
}

函数节流

函数节流:当事件持续触发时,保证一定时间段只执行一次的函数。

函数节流主要有两种实现方法:时间戳和定时器的方式。接下来分别实现这两种方式。

函数节流代码(时间戳):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let throttle = function(fn, delay){
let prev = Date.now();
return function(){
let context = this;
let args = arguments;
let now = Date.now();
if(now - prev >= delay){
fn.apply(context, args);
prev = Date.now();
}
};
};
function handle(){
console.log(Math.random());
}

window.addEventListener('scroll', throttle(handle, 1000));

函数节流代码(定时器):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let throttle = function(fn, delay){
let timer = null;
return function(){
let context = this;
let args = arguments;
if(!timer){
timer = setTimeout(function(){
fn.apply(context, args);
timer = null;
}, delay);
}
}
};

function handle(){
console.log(Math.random())
}

window.addEventListener('scroll', throttle(handle, 1000));

我们可以看出,时间戳方式的节流代码利用闭包,内部函数保存了开始执行时的时间戳,当事件持续触发时,利用先前的时间戳和现在时间戳对比,达到设定的范围执行一次操作函数。定时器方式的节流代码也是类似,在规定的时间段内只维护一个定时器。

** 案例 **限时秒杀活动

我们有一个限时秒杀按钮,用户一般都会在活动倒计时的时候不断地点击按钮,按常规操作,点击一次按钮我们就提交一次请求,这时候的高并发操作肯定不是我们想要的,此时利用节流可以解决问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let btn = ducument.getElementById('show');

function throttle(fn, wait){
let prev = Date.now();
return function(){
let now = Date.now();
if(now - prev >= wait){
fn();
prev = Date.now();
}
}
}

function handle(){
console.log('执行提交操作')
}

btn.onClick = throttle(handle, 1000);

区别:函数节流不管时间触发多频繁,都会保证在规定的时间触发一次;而防抖只是在事件触发的最后一次,在延迟规定的时间后执行函数。