函数节流与函数防抖的区别

 函数节流(throttling)与函数防抖(debouncing)的语义

Throttling will delay executing a function. It will reduce the notifications of an event that fires multiple times.

节流将延迟执行一个函数。它将减少多次发生的事件的通知。
Debouncing will bunch a series of sequential calls to a function into a single call to that function. It ensures that one notification is made for an event that fires multiple times.

防抖将把对一个函数的一系列连续调用捆绑成对该函数的一次调用。它确保对一个多次触发的事件进行一次通知。

If you have a function that gets called a lot - for example when a resize or mouse move event occurs, it can be called a lot of times. If you don't want this behaviour, you can Throttle it so that the function is called at regular intervals. Debouncing will mean it is called at the end (or start) of a bunch of events.

通俗地解释一下:

函数节流:一个函数在一个时间段内只能执行一次

函数防抖:指触发事件后在一个时间段内只能执行一次,如果在这个时间段内又触发了该事件,则会重新计算函数执行时间。

上个图,很容易清楚地看到区别:

函数节流和函数防抖的目的

防止由于浏览器中某些事件频繁被触发,因而频繁操作DOM、资源加载的行为,导致UI停顿甚至浏览器崩溃。

函数节流与函数防抖的实现

函数节流

 1 function throttle(fn, wait) {
 2     var time = null;
 3     return function() {
 4         var context = this;
 5         var args = arguments;
 6         if(!timer) {
 7             timer = setTimeout(function() {
 8                 fn.apply(context, args);
 9             }, wait);
10         }
11     };
12 }
13 
14 function handle() {
15      console.log(Math.random());
16 }
17 
18 window.addEventListener("mousemove", throttle(handle, 1000));

函数防抖

<<JavaScript高级程序设计>>的实现:

1 function debounce(method, context) {
2     clearTimeout(methos.tId);
3     method.tId = setTimeout(function() {
4         method.call(context);
5     }, 100);
6 }
7 //debounce()函数接收两个参数:要执行的函数以及在哪个作用域中执行。如果没有给出第二个参数,那么就在全局作用域内执行该方法。
8 //定时器的ID存储在函数的tId属性中的。第一次把方法传递给dobounce()函数的时候,这个属性可能并不存在。

经过查阅资料,发现<<JavaScript高级程序设计>>把函数防抖写成了函数节流。

来看一下另一种实现方法

 1 var debounce = function(fn, delay){
 2      var timer = null;
 3      return function(){
 4          var context = this, args = arguments;
 5          clearTimeout(timer);
 6          timer = setTimeout(function(){
 7              fn.apply(context, args);
 8          }, delay);
 9      };
10  };
11 
12 
13 window.onresize = debounce(Func, 100);

然而,这种实现方法有缺陷,当你不停地触发某一事件(比如,resize事件),而且触发时间间隔很短,小于debounce(fn, delay)函数设定的时间间隔,则回调函数一直得不到执行。只有在停止触发事件的时候,才最后执行一次回调函数。

下面是防抖函数的拓展:

 1 var debounce = function(fn, delay, mustRunDelay){
 2      var timer = null;
 3      var t_start;
 4      return function(){
 5          var context = this, args = arguments, t_curr = +new Date();
 6          clearTimeout(timer);
 7          if(!t_start){
 8              t_start = t_curr;
 9          }
10          if(t_curr - t_start >= mustRunDelay){
11              fn.apply(context, args);
12              t_start = t_curr;
13          }
14          else {
15              timer = setTimeout(function(){
16                  fn.apply(context, args);
17              }, delay);
18          }
19      };
20  };
21 
22 //mustRunDelay:必然触发的时间间隔
23 window.onresize = debounce(Func, 50, 100);

函数节流和函数防抖的应用场景

函数节流的应用场景:

连续的时间,只需触发一次回调的场景:

  1. 搜索框搜索输入。只需用户在最后一次输入完,再发送请求。
  2. 手机号、邮箱验证输入检测
  3. 窗口大小调整(resize)。只需窗口调整完成后,计算窗口大小。防止重复渲染。

函数防抖的应用场景:

间隔一段时间执行一次回调的场景:

  1. 滚动加载,加载更多或滚动到底部监听
  2. 谷歌搜索框,搜索联想功能
  3. 高频点击提交,表单重复提交

函数节流和函数防抖都可使用setTimeout()实现,但还是建议使用underscoreLodash

参考资料

  1. 浅析函数防抖与函数节流
  2. Debouncing and Throttling Explained Through Explames
  3. 浅谈javascript的函数节流
  4. JS进阶篇1----函数节流(throttle)
原文地址:https://www.cnblogs.com/sparkler/p/13722898.html