节流(throttle)与防抖(debounce)

节流(throttle)和防抖(debounce)在前端使用还是挺频繁的,以前一直是用 Lodash 中提供的方法。今天用这篇文章简单了解下这两个方法的实现原理。

节流和防抖函数都利用了闭包的特性。函数里面嵌套了另一个函数,里面的函数引用了外面函数作用域中定义的变量,导致函数执行完后,这个变量不会被垃圾回收机制回收。因此节流防抖函数可以利用这一特性,根据外函数变量的值,对函数是否再次调用做出针对性处理。

节流(throttle)

在规定时间内内最多触发一次传入的函数。如果在这个规定时间内触发多次函数,则只有一次生效。
应用:上拉加载,监听 scroll 事件,即使页面一直在滑动,也只能每过规定时间触发一次事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 原理:
// 1)先定义一个变量 flag
// 2)当 flag === true,停止执行
// 3)当 flag === false,先将 flag 设置为 true,然后设置定时器,并且在定时器执行完成前,不可设置新的定时器
// 4)经过 delay 时间后,上一步设置的定时器被触发,将 flag 设置为 false,并执行节流函数传入的方法 fun。
// 5)因上一个定时器已被触发,且 flag === false,当节流函数再次被触发时,将可以设置新的定时器
function throttle(fun, delay = 500) {
// 定义一个 Boolean 类型的变量 flag
// true:已经设置过一个定时器,且还没有执行
// false:没有设置过定时器或者上一个定时器已经执行完成
let flag = false;
return function() {
// 如果已经设置过定时器,则不继续执行
if (flag) {
return;
}
// 将 flag 设置为 true,说明下面将设置一个定时器
flag = true;
let _this = this;
let args = arguments;
// 设置一个 delay 后执行的定时器
setTimeout(function() {
// 将 flag 设置为 false,且会执行节流函数接收到的函数 fun
// 这个定时器执行完成后,节流函数可以设置新的定时器
flag = false;
fun.apply(_this, args);
}, delay);
}
}

防抖(debounce)

在事件被触发n秒后再执行,如果在这n秒内又被触发,则重新计时。
应用:输入框联想搜索,监听 input 事件,只有用户在规定时间内没有输入新的内容时,才会触发事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 原理:
// 1)先定义一个 timer 变量
// 2)清掉上一个定时器
// 3)设置新的定时器,并赋值给 timer
function debounce(fun, delay = 500) {
// 先定义一个 timer 变量,会将下面设置的定时器保存到这个变量中
let timer;
return function() {
let _this = this;
let args = arguments;
// 清掉上一个定时器
clearTimeout(timer);
// 设置新的定时器
timer = setTimeout(function() {
fun.apply(_this, args);
}, delay);
}
}