防抖和节流

防抖和节流

处理频繁触发的事件时,如果没有进行限制,每次触发都调用处理函数进行处理不仅会浪费资源,还会降低用户体验,所以需要限制处理函数的调用频率,这便是用到防抖和节流的地方。

函数防抖

当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。

函数防抖的一个典型应用场景是根据 input 的输入内容搜索相关信息,如果 input 内容每次改变都发起搜索请求,则会在短时间内发次多个请求,这种情况下,对事件处理函数进行防抖处理,在给定的时间段 T 内,input 内容没有改变,才发起搜索请求。

1
2
3
4
5
6
7
8
9
10
// 一个简单的防抖函数
function debounce(fn, wait) {
let timeout = null;
return function() {
if (timeout !== null) {
clearTimeOut(timeout);
}
timeout = setTimeOut(fn, wait);
};
}

函数节流

当持续触发事件时,保证一定时间段内只调用一次事件处理函数。

函数节流适合的处理的情况是更高频次的触发事件处理函数的情况,比如 resizemousemovescroll 等,强制事件处理函数以固定频率执行。

  • 时间戳实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 利用时间戳实现节流函数
function throttle(fn, delay) {
let prev = Date.now();
return function() {
let context = this;
let args = arguments;
let now = Data.now();
if (now - prev >= delay) {
fn.apply(context, args);
prev = Date.now();
}
};
}

// 事件处理函数
function handler() {}

// 事件监听
window.addEventListener('scroll', throttle(handler, 500))
  • 定时器实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 利用定时器实现节流函数
function throttle(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 handler() {}

// 事件监听
window.addEventListener('scroll', throttle(handler, 500))
  • 混合实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function throttleFun(fun, duration) {
let timer = null;
let startT = Date.now();
return function() {
const context = this;
const args = arguments;
const remaining = duration - ( startT - Date.now());
clearTimeout(timer);
if (remaining <= 0) {
fun.apply(context, args);
startT = Date.now();
} else {
timer = setTimeout(fun, remaining);
}
}
}

防抖和节流的区别

防抖将几次操作合并为一次操作,节流则保证一段时间内只触发一次函数。

函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。

作者

Y2hlbmdsZWk=

发布于

2018-03-19

更新于

2021-09-01

许可协议