• 1.避免全域性查詢:
 <script type="text/javascript">
function updateUI(){
var imgs=document.getElementsByTagName("img");
for(var i=0,len=imgs.length;i<len;i++){
imgs[i].title=document.title+"image"+i;
}
var msg=document.getElementById("msg");
msg.innerHTML="updated!"
}
updateUI();
</script>

可能優化指令碼效能最重要的就是:注意全域性查詢。使用全域性變數和函式的開銷比區域性變數更大,因為涉及作用域鏈上的查詢。以上例子包含了三個對全域性document物件的引用。當圖片特別多時,會造成對此作用域鏈上的查詢。在這裡,可以建立一個指向document物件的區域性變數。來改進效能。如下:

 1 <script type="text/javascript">
2 function updateUI(){
3 var doc=document;
4 var imgs=doc.getElementsByTagName("img");
5 for(var i=0,len=imgs.length;i<len;i++){
6 imgs[i].title=doc.title+"image"+i;
7 }
8 var msg=doc.getElementById("msg");
9 msg.innerHTML="updated!"
10 }
11 updateUI();
12 </script>

在這裡,首先將document物件儲存在本地的doc變數中,後邊的引用均為該本地變數,現在函式只有一次全域性查詢,肯定更快。

  • 2.避免with語句

和函式相同,with會建立自己的作用域。從而增加其中執行程式碼的作用域鏈長度。由於額外作用域的查詢,在with語句中執行的程式碼肯定比外面執行的程式碼要慢。如下:

     function updateBody(){
with(document.body){
alert(tagName);
innerHTML="hello world!";
}
}
updateBody();

改進:雖然使用with語句可以建立document.body的作用域,在內部直接呼叫它的方法和屬性即可。但可以使用區域性變數來達到相同的效果。

     function updateBody(){
var body=document.body;
alert(body.tagName);
body.innerHTML="hello world!";
}
updateBody();

以上均為:需要不斷查詢作用域鏈,從而造成開銷。可通過建立區域性變數的方法。

  • 選擇正確方法
  1. 物件屬性查詢:使用變數和陣列要比訪問物件上的屬性更高效。物件上的屬性查詢花費時間比較長,因需要在原型鏈中對該屬性進行一次搜尋。所以:一旦多次用到物件屬性,應該將其儲存在區域性變數中。
  2. 優化迴圈:   (1).減值迭代  (2)簡化終止條件  (3)簡化迴圈體   (4)使用後測試迴圈

(1):大多數迴圈使用從0開始、增加到某個特定值的迭代器。在很多情況下,從最大值開始,在迴圈中不斷減值的迭代器更高效。

(2):由於每次迴圈都會計算終止條件,所以必須保證終止條件的簡單,避免屬性查詢和其他操作。

(3):確保迴圈體的優化。

(4):使用後測試優化---最常使用for迴圈和while迴圈 都屬於前測試迴圈。而do-while這種後測試迴圈,避免終止條件的計算,運算更快。

  • 最小化語句數
  1. 多個變數宣告:變數宣告只用一個var語句,之後用逗號隔開。比單個變數分別宣告要快很多。
  2. 插入迭代值 :當使用迭代值時(在不同位置進行增加和減少的值),儘可能合併語句。如:
        var name=values[i];
    i++; 更正為:
    var name=values[i++];
  3. 使用陣列和物件字面量:

  • 優化DOM互動
  1. 最小化現場更新:一旦訪問的DOM部分是已經顯示的頁面的一部分,那麼就要進行現場更新。即需要對頁面對使用者的顯示進行更新。例如:

        var list=document.getElementById("list");
    for(var i=0;i<10;i++){
    var item=document.createElement("li");
    list.appendChild(item);
    item.appendChild(document.createTextNode("item"+i));
    }

因為每次新增專案時都要有兩個現場更新,新增<li>元素和新增文字節點。

解決方法:第一種,將列表從頁面移除,最後進行更新,最後將列表插入原位置。不理想:每次頁面更新會有閃爍。

第二種,使用文件片段來構建DOM結構,接著將其新增到list元素。片段本身不會被新增,片段中的子節點會被新增到目標。

  •      var list=document.getElementById("list"),
    fragment=document.createDocumentFragment(),
    item,
    i;
    for(i=0;i<10;i++){
    item=document.createElement("li");
    fragment.appendChild(item);
    item.appendChild(document.createTextNode("item"+i));
    }
    list.appendChild(fragment);

2.使用innerHTML。建立一個字串然後一次性呼叫innerHTML要比呼叫innerHTML多次快的多。

3.使用事件代理。頁面上的事件處理程式的數量和頁面響應使用者互動的速度之間有個負相關,為了減少這種懲罰,最好事件代理:利用事件冒泡,任何可以冒泡的事件都不僅僅可以可以在事件目標上進行處理,目標的任何元件節點也能處理。

4.注意HTMLCollection。任何時候訪問HTMLCollection,不管屬性還是方法,都是在文件上進行查詢,開銷比較昂貴。。要儘量最小化訪問。優化的重點部分是迴圈。如:

     var image=document.getElementsByTagName("img"),
i,
len;
for(var i=0,len=image.length;i<len;i++){
//處理
}

優化的關鍵:長度length存入變數len,而不是每次都去訪問HTMLCollection的length屬性。在迴圈中使用HTMLCollection時,下一步應該是獲取要使用專案的引用,避免在迴圈體內多次呼叫HTMLCollection。

     var image=document.getElementsByTagName("img"),
i,
len;
for(var i=0,len=image.length;i<len;i++){
img=image[i];
}

這樣,在迴圈中就沒有理由再去訪問image的HTMLCollection。

注意:在編寫JavaScript時,要清楚何時返回HTMLCollection物件。這樣就可以最小化的訪問。以下情況下均返回HTMLCollection物件:

  1. 呼叫getElementsByTagName()
  2. 獲得元素的childNodes屬性。
  3. 獲取元素的attributes屬性。
  4. 訪問特殊集合,如document.forms、document.images等。