淺談javascript函數節流

什麼是函數節流?ajax

     

函數節流簡單的來講就是不想讓該函數在很短的時間內連續被調用,好比咱們最多見的是窗口縮放的時候,常常會執行一些其餘的操做函數,好比發一個ajax請求等等事情,那麼這時候窗口縮放的時候,有可能連續發多個請求,這並非咱們想要的,或者是說咱們常見的鼠標移入移出tab切換效果,有時候連續且移動的很快的時候,會有閃爍的效果,這時候咱們就可使用函數節流來操做。你們都知道,DOM的操做會很消耗或影響性能的,若是是說在窗口縮放的時候,爲元素綁定大量的dom操做的話,會引起大量的連續計算,好比在IE下,過多的DOM操做會影響瀏覽器性能,甚至嚴重的狀況下,會引發瀏覽器崩潰的發生。這個時候咱們就可使用函數節流來優化代碼了~瀏覽器


函數節流的基本原理:閉包

     

使用一個定時器,先延時該函數的執行,好比使用setTomeout()這個函數延遲一段時間後執行函數,若是在該時間段內還觸發了其餘事件,咱們可使用清除方法 clearTimeout()來清除該定時器,再setTimeout()一個新的定時器延遲一下子執行。app


咱們先來看一個簡單的window.resize的demo例子,好比我先定義一個全局變量count=0;當我觸發一次window.resize的時候,該全局變量count++; 咱們來看看在控制檯中打印出count的效果;JS代碼以下:dom


var count = 0;函數

window.onresize = function(){性能

    count++;測試

    console.log(count);優化

}this


執行截圖效果以下:



如上resize的代碼,簡單的縮放一次就打印出屢次,這並非咱們想要的效果,這是簡單的測試,那若是咱們換成ajax請求的話,那麼就會縮放一次窗口會連續觸發屢次ajax請求,下面咱們試着使用函數節流的操做試試一下;


函數節流的第一種方案封裝以下:


function throttleFunc(method,context){

     clearTimeout(method.tId);

     method.tId = setTimeout(function(){

         method.call(context);

     },100);

}


咱們再來封裝一下窗口縮放的demo


var count = 0;

function myFunc() {

   count++;

   console.log(count);

}

window.onresize = function(){

    throttleFunc(myFunc);

}

function throttleFunc(method,context){

     clearTimeout(method.tId);

     method.tId = setTimeout(function(){

         method.call(context);

     },100);

}


如上代碼,咱們再來看看效果,窗口縮放和放大效果會看到,只執行了一次;打印了一次。


上面的代碼使用一個定時器每隔100毫秒執行一次;


咱們也可使用閉包的方法對上面的函數進行再封裝一下;


函數節流的第二種封裝方法以下:


function throttle(fn, delay){

     var timer = null;

     return function(){

         var context = this,

             args = arguments;

         clearTimeout(timer);

         timer = setTimeout(function(){

             fn.apply(context, args);

         }, delay);

     };

};


上面第二種方案是使用閉包的方式造成一個私有的做用域來存放定時器timer,第二種方案的timer是經過傳參數的形式引入的。


調用demo代碼以下:


var count = 0;

function myFunc() {

    count++;

    console.log(count);

}

var func = throttle(myFunc,100);

window.onresize = function(){

   func();

}        

function throttle(fn, delay){

     var timer = null;

     return function(){

         var context = this,

             args = arguments;

         clearTimeout(timer);

         timer = setTimeout(function(){

             fn.apply(context, args);

         }, delay);

     };

};


函數節流的基本思想是:就是想讓一個函數不要執行的太頻繁,減小一些過快的來節流函數,好比當咱們改變窗口縮放的時候,瀏覽器的間隔有多是16ms,這是瀏覽器自帶的時間間隔,咱們沒法改變,而咱們經過節流的方式能夠試着改變一下這個間隔,儘可能稍微延長下這個調用時間,所以咱們能夠封裝以下函數:


函數節流的第三種封裝方法


function throttle3(fn,delay,runDelay){

      var timer = null;

      var t_start;

      return function(){

         var context = this,

             args = arguments,

             t_cur = new Date();

         timer & clearTimeout(timer);

         if(!t_start) {

             t_start = t_cur;

         }

         if(t_cur - t_start >= runDelay) {

              fn.apply(context,args);

              t_start = t_cur;

         }else {

              timer = setTimeout(function(){

                  fn.apply(context,args);

               },delay);

         }

    }

}


調用demo以下:


var count = 0;

function myFunc() {

   count++;

   console.log(count);

}

var func = throttle3(myFunc,50,100);

window.onresize = function(){

   func();}

function throttle3(fn,delay,runDelay){

      var timer = null;

      var t_start;

      return function(){

          var context = this,

              args = arguments,

              t_cur = new Date();

          timer & clearTimeout(timer);

          if(!t_start) {

              t_start = t_cur;

          }

          if(t_cur - t_start >= runDelay) {

                fn.apply(context,args);

                t_start = t_cur;

          }else {

                timer = setTimeout(function(){

                     fn.apply(context,args);

                },delay);

          }

      }

}


上面的第三個函數是封裝後的函數,有三個參數,咱們能夠本身設置觸發事件的時間間隔,則意味着,如上代碼50ms連續調用函數,後一個調用會把前一個調用的等待處理掉,但每隔100ms會至少執行一次,具體使用哪種方式只要看本身的權衡,可是我我的以爲第二種封裝函數的方式夠咱們使用的,固然聽說第三種方式性能更好~

相關文章
相關標籤/搜索