首頁 > web前端 > js教程 > 主體

談談JS中的函數節流

大家讲道理
發布: 2016-11-11 10:04:20
原創
1410 人瀏覽過

函數節流的目的

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

函數節流的原理

某些程式碼不可以在沒有間斷的情況連續重複執行。第一次呼叫函數,建立一個定時器,在指定的時間間隔之後執行程式碼。當第二次呼叫函數時,它會清除前一次的計時器並設定另一個。如果前一個定時器已經執行過了,這個操作就沒有任何意義。然而,如果前一個定時器尚未執行,其實就是將其替換為新的定時器。目的是只有在執行函數的請求停止了一段時間之後才執行。

函數節流的基本模式

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事件處理函數,在控制台輸出我輸入的內容。

測試主要代碼:

<input id="search" type="text" name="search">
登入後複製
登入後複製
   
function queryData(text){
    console.log("搜索:" + text);
  }
var input = document.getElementById("search");
  input.addEventListener("keyup", function(event){ queryData(this.value);
});
登入後複製

結果如圖:

談談JS中的函數節流


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

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

測試主要代碼:

<input id="search" type="text" name="search">
登入後複製
登入後複製
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);
}
登入後複製

結果如圖:

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

談談JS中的函數節流


好吧,或許看不出端倪。其實問題就是,假如我不斷地輸入,輸入了很多內容,但是我每兩次之間的輸入間隔都小於自己設定的delay值,那麼,這個queryData搜尋函數就一直無法得到呼叫。實際上,我們更希望的是,當達到某個時間值時,一定要執行一次這個搜尋函數。所以,就有了函數節流的改進模式。

③函數節流增強版

測試的主要程式碼:

<input id="search" type="text" name="search">
登入後複製


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){ <br>            //当前时间与上一次函数被执行的时间作差,与mustApplyTime比较,若大于,则必须执行一次函数,若小于,则重新设置计时器
     fn.call(context,text);
     fn._start=fn._cur;
  }else{
    fn.timer=setTimeout(function(){
    fn.call(context,text);
    },deley);
  }
}
登入後複製


測試結果如圖:

談談JS中的函數節流


顯然,連續的輸入,到一定時間間隔之後,queryData又是一定時間間隔的調用。這既達到了節流的目的,又不會影響使用者體驗。

④進一步的最佳化

進一步的話,就是可以在呼叫throttle函數之前,先對輸入的內容進行判斷,若其值為空、值不變都不用再調用。這裡就不詳說了。

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!