stephen's blog

[object Object] object(s)
 

深入浅出throttle和debounce

前言

之前我在写一个获取github用户信息小应用的时候,遇到了一个问题: 由于我在input上绑定了keyup的监听事件并且回调执行ajax请求,每按下一次键盘键就会发出一次ajax请求,显然频繁的网络请求会造成很大的性能问题。这里的解决办法就是用函数去抖(debounce)。那么什么是函数去抖?他的基友函数节流(throttle)又是什么?他们有什么区别?他们应用的场景有分别是什么?下面一一来解答。

函数去抖

简单来说,函数去抖背后的思想指的是 某函数只有在过完一段时间后并且该段时间内不被调用才会被执行。一旦在指定的时间间隔内调用该函数,该函数就不会被执行。拿上面例子来说,在没有去抖之前:

1
2
3
4
5
6
7
function ajax(content) {
console.log('ajax request ' + content)
}
var input = document.getElementById('search')
input.addEventListener('keyup', function(e) {
ajax(e.target.value)
})

可以看到,每按下一次键盘键就会发送一次ajax请求。现在用debounce()方法来改进:

jsbin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function debounce(func, delay) {
return function(args) {
var _this = this
var _args = args
clearTimeout(func.id)
func.id = setTimeout(function() {
func.call(_this, _args)
}, delay)
}
}
function ajax(value) {
console.log('ajax request ' + value)
}
var debounceAjax = debounce(ajax, 1000)
var input = document.getElementById('search')
input.addEventListener('keyup', function(e) {
debounceAjax(e.target.value)
})

可以看到当你键入值的时候,并不会发送ajax请求,当停止输入并且在指定间隔内没有输入的时候,才会执行相应的回调函数。下面我们来讲讲他的好基友,函数节流(throttle)。

函数节流

函数节流指的是 某函数在指定的一个时间段周期性的间断执行。 什么意思呢,举上面的例子,当在input中不断键入数值的时候,debounce是在你停止输入一段时间后执行回调函数,而throttle则是在你输入过程中每隔一段固定的时间就执行回调函数。

jsbin

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
function throttle(func, delay) {
var last, deferTimer
return function() {
var _this = this
var _args = arguments
var now = +new Date()
if(last && now < last + delay) {
clearTimeout(deferTimer)
deferTimer = setTimeout(function() {
last = now
func.apply(_this, _args)
}, delay)
}else {
last = now
func.apply(_this, _args)
}
}
}
function ajax(value) {
console.log('ajax request ' + value)
}
var throttleAjax = throttle(ajax, 1000)
var input = document.getElementById('search')
input.addEventListener('keyup', function(e) {
throttleAjax(e.target.value)
})

可以看出,当我在input中不断键入值时,ajax回调函数每过1s执行一次。

异同

从上面的内容可以知道,函数去抖和函数分流都是解决某一事件频繁触发的问题,比如input的ajax请求、scroll事件等等。即使如此,他们的实现原理却大相庭径,简单来说,函数去抖在一段时间只执行一次,而函数节流则是间隔时间段执行。比如,小明吃饼干,有两种吃法,第一种是每过一段时间间隔吃一块饼干,这是函数节流,第二种是第一块饼干吃完后得过一段时间才能吃第二块饼干,期间不能吃饼干,这是函数去抖。

应用场景

参考: https://github.com/hanzichi/underscore-analysis/issues/20