今晚月色真美

概念

通常情况下,声明在一个函数中的函数,叫做闭包函数,在Javascript语言中,只有函数内部的子函数才能读取局部变量:

1
2
3
4
5
6
7
// 闭包函数
function f1(){
var n;
return function () {
n ++;
}
}

优缺点

优点

让外部访问函数内部变量成为可能
可以避免使用全局变量,防止全局变量污染

缺点

局部变量会常驻在内存中,会造成内存泄漏(有一块内存空间被长期占用,而不被释放)

防抖

设想有此场景:输入框中内容变化需要实时请求接口以获取最新搜索结果,如果在输入完成前输入框内容每变化一下都去请求接口,会造成很多不必要的请求,大大增加服务器压力。

解决思路:有变化时延迟一段时间再执行function,若在这段延迟时间内又有新变化,则重新开始延迟

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
// 定时器期间,有新操作时,清空旧定时器,重设新定时器
var debounce = (fn, wait) => {
let timer, timeStamp=0;
let context, args;

let run = ()=>{
timer= setTimeout(()=>{
fn.apply(context,args);
},wait);
}

let clean = () => {
clearTimeout(timer);
}

return function() {
context = this;
args = arguments;
let now = (new Date()).getTime();
if (now-timeStamp < wait) {
console.log('reset',now);
// 清除定时器,并重新加入延迟
clean();
run();
} else {
console.log('set',now);
run(); // last timer alreay executed, set a new timer
}
timeStamp = now;
}
}

代码进一步优化:周期内有新事件触发时,重置定时器开始时间戳,定时器执行时,判断开始时间戳,若开始时间戳被推后,重新设定延时定时器;加入是否立即执行参数。

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
// 增加前缘触发功能
var debounce = (fn, wait, immediate=false) => {
let timer, startTimeStamp=0;
let context, args;

let run = (timerInterval) => {
timer= setTimeout(() => {
let now = (new Date()).getTime();
let interval = now-startTimeStamp
if(interval < timerInterval) { // the timer start time has been reset,so the interval is less than timerInterval
console.log('debounce reset',timerInterval-interval);
startTimeStamp = now;
run(wait-interval); // reset timer for left time
} else {
if (!immediate) {
fn.apply(context,args);
}
clearTimeout(timer);
timer=null;
}
}, timerInterval);
}

return function() {
context = this;
args = arguments;
let now = (new Date()).getTime();
startTimeStamp = now; // set timer start time

if(!timer) {
console.log('debounce set',wait);
if(immediate) {
fn.apply(context,args);
}
run(wait); // last timer alreay executed, set a new timer
}
}
}

节流

设想有此场景:有‘搜索’按钮,每点击一次都会重新请求接口,获取并渲染页面表格最新数据,假如短时间内连续点击按钮,依然会造成很多不必要的请求
解决思路:在一段时间内只执行最后一次function

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 定时器期间,只执行最后一次操作
var throttling = (fn, wait) => {
let timer;
let context, args;

let run = () => {
timer=setTimeout(()=>{
fn.apply(context,args);
clearTimeout(timer);
timer=null;
},wait);
}

return function () {
context=this;
args=arguments;
if(!timer){
console.log("throttle, set");
run();
}else{
console.log("throttle, ignore");
}
}
}

// 增加前缘
var throttling = (fn, wait, immediate) => {
let timer, timeStamp=0;
let context, args;

let run = () => {
timer=setTimeout(()=>{
if(!immediate){
fn.apply(context,args);
}
clearTimeout(timer);
timer=null;
},wait);
}

return function () {
context=this;
args=arguments;
if(!timer){
console.log("throttle, set");
if(immediate){
fn.apply(context,args);
}
run();
}else{
console.log("throttle, ignore");
}
}
}

总结

防抖及节流都是使用闭包函数来应用的实际场景,平时也应注意合理使用闭包函数,避免性能消耗过多。

 评论

本站总字数统计:49.8k

感谢您的浏览, 本站总访问量为 次 。
载入天数...载入时分秒...