函数节流(Throttling)和函数防抖(Debouncing)

函数节流(Throttling)和函数防抖(Debouncing)

函数节流和函数防抖是平时组做也页面性能优化的两种重要技巧。他们在各类需要频繁触发的工作场景中,
比如对页面onscrollonresize事件的监听,解决由于这种频繁触发的高消耗操作会带来
性能问题。

平时在应用中,使用较多的也广为人知的是函数节流(throtting),相对来说函数防抖(debouncing)
使用得较少,两个的区别也很模糊,这篇主要从具体实现上区分throttle和debounce。

函数节流(throttling)

首先来看函数节流。函数节流的作用是,不论触发频率,单位时间内指定函数只被调用一次。就像涓涓细流一样
平缓。
具体代码实现如下:

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
/**
* - 节流函数
* @param {Function} fn - 要执行的函数
* @param {Number} interval - 延迟执行的时间
*/
function throttle(fn, interval) {
var timer = null
var firstTime = true
return function () {
var self = this
var args = arguments
if (firstTime) { // 第一次则立即执行
fn.apply(this, args)
return firstTime = false
}
if (timer) { // 上次延迟操作还未被执行
return false
}
timer = setTimeout(function () { // 延迟执行
clearTimeout(timer)
timer = null
fn.apply(self, args)
}, interval || 500)
}
}

可以使用ES6语法来简化Throtting函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function throttle(fn, interval = 500) {
var timer
var firstTime
return function (...args) {
if (firstTime) {
fn.apply(this, args)
return firstTime = false
}
if (!timer) {
timer = setTimeout(() => timer = null, interval) // 固定时间清除定时器id
return fn.apply(this, args) // 不在定时器回调里调用故不用指定this(此处也可以按照上面思路在回调中调用,箭头函数自动绑定this)
}
}
}

函数防抖(Debouncing)

相对于函数节流,函数防抖是等待事件触发之后等一段时间在执行,如果触发频率高于设定的延迟时间,则一直等下下去
看到一个形象的比喻就是乘坐电梯的时候,如果电梯关闭时间是10s,这10s时间内有人进出电梯那么
电梯就会再等10s知道10s之内无人出入才会关门
防抖函数实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* - 防抖函数
* @param {Function} fn - 要执行的函数
* @param {Number} interval - 延迟执行的时间
*/
function debounce(fn, interval) {
var timer
var firstTime = true
return function () {
clearTimeout(timer) // 每次触发都先清除定时器是之处于等待状态
var self = this
var args = arguments
if (firstTime) {
firstTime = false
return fn.apply(this, args)
}
timer = setTimeout(function () {
fn.apply(self, args)
}, interval || 500)
}
}

同样,使用ES6语法可以简化代码:

1
2
3
4
5
6
7
8
9
10
11
12
function debounce(fn, interval = 500) {
var timer
var firstTime = true
return function (...args) {
clearTimeout(timer)
if (firstTime) {
firstTime = false
return fn.apply(this, args)
}
timer = setTimeout(() => fn.apply(this, args), interval)
}
}

函数节流和函数防抖功能相似,却有着不同的使用场景。根据需求合理使用会获得很大得性能提升,在平时项目中应该根据应用场景
多多使用。