1. 程式人生 > >JS效能優化 -- 函式節流

JS效能優化 -- 函式節流

一、函式節流的概念、主要用途及意義

概念:函式節流是通過一個定時器,阻斷連續重複的函式呼叫,從而一定程度上優化效能。

用途:主要用於使用者介面呼叫的函式,如:resize、mousemove、keyup事件的監聽函式。
這類監聽函式的主要特徵:
1、短時間內連續多次重複觸發;
2、大量的DOM操作。

意義:在使用者察覺範圍外,降低函式呼叫的頻率,從而提升效能

二、函式節流的原理

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

三、具體用法

例如:
1、使用onresize 事件處理程式的時候容易發生,當調整瀏覽器大小的時候,該事件會連續觸發。在onresize 事件處理程式內部如果嘗試進行DOM 操作,其高頻率的更改可能會讓瀏覽器崩潰。
2、我們常見的一個搜尋的功能,我們一般是繫結keyup事件,每按下一次鍵盤就搜尋一次。但是我們的目的主要是每輸入一些內容搜尋一次而已。

為了解決這些問題,就可以使用定時器對函式進行節流。

基本模式

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

下面以keyup為例

1、不使用函式節流的情況

<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); });

結果如圖:

這裡寫圖片描述

2、使用基本函式節流的情況

<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);
}

結果如圖:

這裡寫圖片描述

實際上,我們更希望的是,當達到某個時間值時,一定要執行一次這個搜尋函式。所以,就有了函式節流的改進模式。

3、函式節流增強版

<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){ 
  //當前時間與上一次函式被執行的時間作差,與mustApplyTime比較,若大於,則必須執行一次函式,若小於,則重新設定計時器
     fn.call(context,text);
     fn._start=fn._cur;
  }else{
    fn.timer=setTimeout(function(){
    fn.call(context,text);
    },delay);
  }
}

結果如圖:

這裡寫圖片描述

顯然,連續的輸入,到一定時間間隔之後,queryData函式必然會被呼叫,但是又不是頻繁的呼叫。這既達到了節流的目的,又不會影響使用者體驗。

4、進一步的優化

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