談談JS中的函數節流

好吧,一直在秋招中,都沒怎麼寫博客了。。。今天趕忙來補一補才行。。。我發現,在面試中,講到函數節流好像能夠加分,儘管這並非特別高深的技術,下面就聊聊吧! ^_^javascript

備註:如下內容部分來自《JavaScript高級程序設計》html

函數節流的目的java

    從字面上就能夠理解,函數節流就是用來節流函數從而必定程度上優化性能的。例如,DOM 操做比起非DOM 交互須要更多的內存和CPU 時間。連續嘗試進行過多的DOM 相關操做可能會致使瀏覽器掛起,有時候甚至會崩潰。尤爲IE 中使用onresize 事件處理程序的時候容易發生,當調整瀏覽器大小的時候,該事件會連續觸發。onresize 事件處理程序內部若是嘗試進行DOM 操做,其高頻率的更改可能會讓瀏覽器崩潰。又例如,咱們常見的一個搜索的功能,咱們通常是綁定keyup事件,每按下一次鍵盤就搜索一次。可是咱們的目的主要是每輸入一些內容搜索一次而已。爲了解決這些問題,就可使用定時器對函數進行節流面試

函數節流的原理ajax

   某些代碼不能夠在沒有間斷的狀況連續重複執行。第一次調用函數,建立一個定時器,在指定的時間間隔以後運行代碼。當第二次調用該函數時,它會清除前一次的定時器並設置另外一個。若是前一個定時器已經執行過了,這個操做就沒有任何意義。然而,若是前一個定時器還沒有執行,其實就是將其替換爲一個新的定時器。目的是隻有在執行函數的請求中止了一段時間以後才執行。瀏覽器

函數節流的基本模式函數

var processor = {
   timeoutId: null,
     //實際進行處理的方法
   performProcessing: function(){
     //實際執行的代碼
   },
  //初始處理調用的方法
  process: function(){
    clearTimeout(this.timeoutId);
    var that = this;
    this.timeoutId = setTimeout(function(){
      that.performProcessing();
    }, 100);
  }
};
//嘗試開始執行
processor.process();

好吧,看得確實有點迷糊。下面經過一個例子來詳細說明,而且在這個基礎模式之上作一個優化處理。性能

例子場景:實現常見的搜索功能學習

①沒有使用函數節流的狀況下,爲input綁定keyup事件處理函數,在控制檯輸出我輸入的內容。測試

測試主要代碼:

HTMl:
    <input id="search" type="text" name="search">
JS:
    <script>
        function queryData(text){
            console.log("搜索:" + text);
        }
        var input = document.getElementById("search");
        input.addEventListener("keyup", function(event){ queryData(this.value);
        });
    </script>        

結果如圖:

 能夠看出,這種狀況下,每按下一個鍵盤鍵,就輸出了一次。短短的一些內容,輸出了14次,若是每一次都是一次ajax查詢請求的話就發了14個請求了。在性能上的消耗可想而知。

②使用基本的函數節流模式的狀況。

測試主要代碼:

HTML:
    <input id="search" type="text" name="search">
JS:
    <script>
        function queryData(text){
            console.log("搜索:" + text);
        }
        var input = document.getElementById("search");
        input.addEventListener("keyup", function(event){
            throttle(queryData, null, 500, this.value);
            // queryData(this.value);
        });
        
        function throttle(fn,context,delay,text){
            clearTimeout(fn.timeoutId);
            fn.timeoutId = setTimeout(function(){
                fn.call(context,text);
            },delay);
        }
   </script>

結果如圖:

 能夠看出,這種狀況下,輸入了好一些內容,只輸出了一次,由於測試的時候設置了兩次輸入間隔是500ms,實際應用可根據狀況設置。顯然,這在性能上大大滴獲得了優化。不過,這樣的話,有一個新問題,以下圖:

好吧,或許看不出端倪。其實問題就是,假如我不斷地輸入,輸入了不少內容,可是我每兩次之間的輸入間隔都小於本身設置的delay值,那麼,這個queryData搜索函數就一直得不到調用。實際上,咱們更但願的是,當達到某個時間值時,必定要執行一次這個搜索函數。因此,就有了函數節流的改進模式。

③函數節流加強版

測試的主要代碼:

HTML:
    <input id="search" type="text" name="search">
JS:
    <script>
        function queryData(text){
            console.log("搜索:" + text);
        }
        var input = document.getElementById("search");
        input.addEventListener("keyup", function(event){
            throttle(queryData, null, 500, this.value,1000);
            // throttle(queryData, null, 500, this.value);
            // queryData(this.value);
        });
        
        function throttle(fn,context,delay,text,mustApplyTime){
            clearTimeout(fn.timer);
            fn._cur=Date.now();  //記錄當前時間

            if(!fn._start){      //若該函數是第一次調用,則直接設置_start,即開始時間,爲_cur,即此刻的時間
                fn._start=fn._cur;
            }
            if(fn._cur-fn._start>mustApplyTime){ 
//當前時間與上一次函數被執行的時間做差,與mustApplyTime比較,若大於,則必須執行一次函數,若小於,則從新設置計時器 fn.call(context,text); fn._start
=fn._cur; }else{ fn.timer=setTimeout(function(){ fn.call(context,text); },delay); } } </script>

測試結果如圖:

顯然,連續的輸入,到必定時間間隔以後,queryData函數必然會被調用,可是又不是頻繁的調用。這既達到了節流的目的,又不會影響用戶體驗。

④進一步的優化

   進一步的話,就是能夠在調用throttle函數以前,先對輸入的內容進行判斷,若其值爲空、值不變都不用再調用。這裏就不詳說了。

 

更多學習連接

詳細改進實例

節流與去抖

 

  好吧,就到這了,若是有錯誤的地方,還要指正哦...^_^

相關文章
相關標籤/搜索