闭包应用之——函数节流&函数防抖

以下场景往往由于事件频繁被触发,因而频繁执行DOM操作、资源加载等重行为,导致UI停顿甚至浏览器崩溃:

  1. window对象的resizescroll事件

  2. 拖拽时的mousemove事件

  3. 射击游戏中的mousedownkeydown事件

  4. 文字输入、自动完成的keyup事件

所以为了解决这些问题我们就可以引入函数节流(Throttle) & 函数防抖(Debounce)的概念,同时也是闭包的一个用途

函数节流(Throttle

函数节流旨在固定函数的执行速率,在一个事件周期内只可以被触发一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
function throttle(fn, delay){
var timer
return function(){
var context = this
var args = arguments

clearTimeout(timer)

timer = setTimeout(function(){
fn.apply(context, args)
}, delay)
}
}

函数防抖(Debounce

Debounce其实是从机械开关和继电器的“去弹跳”衍生而来。基本思路是讲多个信号合并为一个信号

JavaScript中Debounce函数所做的事情是强制一个函数再某个连续的时间段内只执行一次,哪怕他本会被调用多次

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
function debounce(fn, threshhold){
var last // 记录上次执行时间
var timer
threshhold || (threshhold = 250)

// 返回的函数,每过 threshhold ms 执行一次
return function(){
var context = this
var args = arguments
var now = new Date()

// 若距上次执行 fn 函数的时间小于 threshhold 则放弃
// 否则执行 fn ,并重新计时
if(last && now<last+threshhold){
clearTimeout(timer)

// 保证在当前事件结束后再执行一次 fn
timer= setTimeout(function(){
last = now
fn.apply(context, args)
}, threshhold)
}else{
last = now
fn.apply(context, args)
}
}
}

举个实践中的例子:通过用户的输入实时向服务器发送ajax请求获取数据

1
2
3
$(selector).on('keyup', debounce(function(e){
// 发送ajax
}, 300))