函数的节流与防抖

      当我们在做 WEB 客户端开发时,会经常使用resizescrollmousemoveinput等在极短的时间内高频的调用回调函数。如果回调中又伴随着 DOM 操作,从而引发浏览器的重排与重绘,会造成浏览器非常大的计算压力,同时也会大量占用内存,性能差的浏览器可能就会直接假死,这样会大大降低用户体验。所以我们需要降低触发回调的频率。接下来我们通过函数节流和防抖看下如何降低回调的频率。

函数节流(throttle)

      节流指的是在规定的单位时间内,只能有一次触发事件的回调函数执行,如果在规定的单位时间内某事件被触发多次,那么只能有一次生效。我们以监听window对象的scroll事件为例:

无节流时:

1
2
3
4
5
6
 $(window).on(
"scroll",
function() {
console.log("触发滚动事件");
}
);

无节流

      在没有加上函数节流之前,滚动的时候,浏览器会无时无刻地去触发滚动的方法,这样做事比较消耗性能的。在实际场景中,我们需要的是滚动时每隔一段时间去执行一次滚动的回调,而不是无时无刻的。所以我们需要加上函数节流,当触发滚动时,每隔一个单位时间才会去执行滚动的回调。

节流后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function throttle(callback, duration = 300) {
//触发滚动方法时计算当前时间
let time = new Date().getTime();
return function() {
//执行回调函数前再次计算当前时间
let nowTime = new Date().getTime();
//确保下次执行必须在300ms以后
if (nowTime - time > duration) {
//执行回调
callback();
//执行后需要把当前时间变成执行回调后的时间
time = nowTime;
}
};
}
$(window).on(
"scroll",
throttle(function() {
console.log("触发滚动事件");
}, 500)
);

      我们用一张图简单看下节流的具实现思路把。最开始会先执行 f1 函数,当 f2 又被触发后,先去判断它是否在单位时间 500ms 内,如果在,则不执行。接下来 f3 又被触发了,同理也是判断是否在单位时间 500ms 内,不在的话,则执行 f3。


节流

节流应用场景



  • 短时间高频触发scroll、touchmove等事件

  • DOM元素拖拽

函数防抖(debounce)

      节流指的是在规定的单位时间内,只能有一次触发事件的回调函数执行,如果在同一单位时间内某事件被触发多次,那么只能有一次生效,我们用输入框的input事件为例来看看函数防抖。

1
2
3
4
5
6
$("#debounce").on(
"input",
function() {
console.log($("#debounce").val());
}
);

未防抖

      我们可以看到,只要输入框值改变,就会触发回调。从资源上说,这是一种浪费的行为,而且在实际场景中,也是用户输入完整的字符后,才需要执行进一步的回调,接下来,我们用函数防抖优化下:

防抖后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function debounce(callback, delay = 500) {
//初设起始时间为null
var time = null;
return function() {
//每次执行后都清空时间
clearTimeout(time);
time = setTimeout(() => {
//延迟500ms后执行回调
callback();
}, delay);
};
}
$("#debounce").on(
"input",
debounce(function() {
console.log($("#debounce").val());
}, 600)
);

      我们还是用一张图来看看防抖的实现思路把。当第一次触发了 f1 后,我们先将它延迟 500ms 后执行。如果在 500ms 期间,又触发了一次,我们叫它 f2,则会将 500ms 清空,反正 f1 也还没有执行,则会重新延迟 500ms 后再执行 f2,依次类推。通过闭包保存一个标记用来存储setTimeout返回的值,当再次触发后,就会把前一个setTimeout clear 掉,然后再创建一个新的setTimeout


防抖

防抖应用场景


  • 输入框搜索联想

  • 给按钮加函数防抖防止表单多次提交

  • 对于输入框连续输入进行AJAX验证时,用函数防抖能有效减少请求次数

  • 触发resize,不断的调整浏览器窗口大小

Copyright ©2019 guowj All Rights Reserved.

访客数 : | 访问量 :