防抖和节流在前端性能优化中很常用,防抖和节流都是对一段时间内事件触发函数执行频率的控制;使用场景就是当频繁事件时怎样去处理函数执行。

防抖

在限定时间内,如果事件再次触发,丢弃当前已响应的函数执行,以当前事件响应函数重新计时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function debounce(fn, wait) {
wait = wait || 200;
var timer = null;
return function () {
if (timer) {
clearTimeout(timer);
}
var args = arguments;
var that = this;
timer = setTimeout(function () {
timer = null;
fn.apply(that, args);
}, wait)
}
}
_.debounceUnderscore.js
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
_.debounce = function(func, wait, immediate) {
var timeout, result;

var later = function(context, args) {
timeout = null;
if (args) result = func.apply(context, args);
};

var debounced = restArguments(function(args) {
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(later, wait);
if (callNow) result = func.apply(this, args);
} else {
timeout = _.delay(later, wait, this, args);
}

return result;
});

debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
};

return debounced;
};

节流

在限定时间内,如果事件再次触发,忽略事件响应,当到达时间后函数执行后再开始事件响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function throttle(fn, wait) {
wait = wait || 200;
var timer = null;
return function () {
if (timer) {
return;
}
var args = arguments;
var that = this;
timer = setTimeout(function () {
fn.apply(that, args);
timer = null;
}, wait)
}
}
_.debounceUnderscore.js
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
30
31
32
33
34
35
36
37
38
39
40
_.throttle = function(func, wait, options) {
var timeout, context, args, result;
var previous = 0;
if (!options) options = {};

var later = function() {
previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};

var throttled = function() {
var now = _.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};

throttled.cancel = function() {
clearTimeout(timeout);
previous = 0;
timeout = context = args = null;
};

return throttled;
};