前端之节流和防抖

2019/12/17 Blog

前端之节流和防抖

在前端开发中,我们会遇到一些持续触发的事件,但是我们并不希望那样的去触发它,那么节流和防抖都是用来防止一些函数不必要的连续执行的。

在 明白防抖和节流之前一定要先明白两个定时器的用法

  • setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。
  • setTimeout(code,millisec) :code是要调用的函数后要执行的 JavaScript 代码串。millisec是在执行代码前需等待的毫秒数。
  • setTimeout() 只执行 code 一次。如果要多次调用,请使用 setInterval() 或者让 code 自身再次调用 setTimeout()。

  • setInterval以指定时间为周期循环,会一直执行,直到 clearTimeout ()被调用

节流

首先来说节流是什么?

  • 节流就是节省流量,一点一点的用流量,不要一下子全用完了,一段时间用一点。

  • 当持续触发事件时,保证一定时间段内只调用一次事件处理函数。

  • 坦白说就是当要连续触发一个事件的时候,一个事件执行完后,等待一段时间再继续执行它。

  • 节流throttle代码(时间戳):

  • var throttle = function(func, delay) {            
      var prev = Date.now();            
      return function() {                
        var context = this;                
        var args = arguments;                
        var now = Date.now();                
        if (now - prev >= delay) {                    
          func.apply(context, args);                    
          prev = Date.now();                
        }            
      }        
    }        
    function handle() {            
      console.log(Math.random());        
    }        
    window.addEventListener('scroll', throttle(handle, 1000));
    
  • 当高频事件触发时,第一次会立即执行(给scroll事件绑定函数与真正触发事件的间隔一般大于delay,如果你非要在网页加载1000毫秒以内就去滚动网页的话,我也没办法o(╥﹏╥)o),而后再怎么频繁地触发事件,也都是每delay时间才执行一次。而当最后一次事件触发完毕后,事件也不会再被执行了 (最后一次触发事件与倒数第二次触发事件的间隔小于delay,为什么小于呢?因为大于就不叫高频了呀

  • 节流throttle代码(定时器):

  • // 节流throttle代码(定时器):
    var throttle = function(func, delay) {            
        var timer = null;            
        return function() {                
            var context = this;               
            var args = arguments;                
            if (!timer) {                    
                timer = setTimeout(function() {                        
                    func.apply(context, args);                        
                    timer = null;                    
                }, delay);                
            }            
        }        
    }        
    function handle() {            
        console.log(Math.random());        
    }        
    window.addEventListener('scroll', throttle(handle, 1000));
    
  • 当触发事件的时候,我们设置一个定时器,再次触发事件的时候,如果定时器存在,就不执行,直到delay时间后,定时器执行执行函数,并且清空定时器,这样就可以设置下个定时器。当第一次触发事件时,不会立即执行函数,而是在delay秒后才执行。而后再怎么频繁触发事件,也都是每delay时间才执行一次。当最后一次停止触发后,由于定时器的delay延迟,可能还会执行一次函数。

    节流中用时间戳或定时器都是可以的。更精确地,可以用时间戳+定时器,当第一次触发事件时马上执行事件处理函数,最后一次触发事件后也还会执行一次事件处理函数。

  • 节流throttle代码(时间戳+定时器):

  • // 节流throttle代码(时间戳+定时器):
    var throttle = function(func, delay) {     
        var timer = null;     
        var startTime = Date.now();     
        return function() {             
            var curTime = Date.now();             
            var remaining = delay - (curTime - startTime);             
            var context = this;             
            var args = arguments;             
            clearTimeout(timer);              
            if (remaining <= 0) {                    
                func.apply(context, args);                    
                startTime = Date.now();              
            } else {                    
                timer = setTimeout(func, remaining);              
            }      
        }
    }
    function handle() {      
        console.log(Math.random());
    } 
    window.addEventListener('scroll', throttle(handle, 1000));
    
  • 在节流函数内部使用开始时间startTime、当前时间curTime与delay来计算剩余时间remaining,当remaining<=0时表示该执行事件处理函数了(保证了第一次触发事件就能立即执行事件处理函数和每隔delay时间执行一次事件处理函数)。如果还没到时间的话就设定在remaining时间后再触发 (保证了最后一次触发事件后还能再执行一次事件处理函数)。当然在remaining这段时间中如果又一次触发事件,那么会取消当前的计时器,并重新计算一个remaining来判断当前状态。

防抖

那么防抖有是什么?

  • 防抖就是防止抖动,防止你持续的抖动触发事件,等抖完了再执行。
  • 当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次 。
  • 如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
/ 防抖
function debounce(fn, wait) {    
    var timeout = null;    
    return function() {        
        if(timeout !== null)   clearTimeout(timeout);        
        timeout = setTimeout(fn, wait);    
    }
}
// 处理函数
function handle() {    
    console.log(Math.random()); 
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));

当持续触发scroll事件时,事件处理函数handle只在停止滚动1000毫秒之后才会调用一次,也就是说在持续触发scroll事件的过程中,事件处理函数handle一直没有执行。

应用场景

  • debounce(防抖)

    • search搜索,用户在不断输入值时,用防抖来节约请求资源。
    • window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
  • throttle (节流)

    • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
    • 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断

Search

    Table of Contents