相信寫代碼對於大部分人都不難,但想寫出高性能的代碼就需要一定的技術積累啦,下面是一些優化JavaScript代碼性能的常見方法。
一.注意作用域
1.避免全局查找
使用全局變量和函數肯定要比局部的開銷更大,因為要涉及作用域鏈上的查找,請看以下函數:
1 function demo1() { 2 var imgs = document.getElementByTagName("img"); //獲取頁面所有img標簽 3 4 for(var i = 0; i <= imgs.length; i++) { 5 imgs[i].title = document.title + "image" + i; 6 } 7 }
上面的代碼每執行一次for循環都會在全局尋找document,一旦循環次數很多,那么就嚴重影響了性能,我們可以在for循環開始之前就把document的引用保存在一個局部變量。改進代碼如下:
1 function demo1() { 2 var imgs = document.getElementByTagName("img"); //獲取頁面所有img標簽 3 var doc = document; //局部引用全局變量document 4 5 for(var i = 0; i <= imgs.length; i++) { 6 imgs[i].title = doc.title + "image" + i; 7 } 8 }
二.選擇正確方法
1.優化循環
1 for(var i = 0; i <=imgs.length; i++) { 2 //執行代碼 3 }
上面代碼每次執行循環都會重新計算imgs的長度,一旦循環次數很多,那么積少成多就會影響到代碼性能,我們只需在for循環執行之前把imgs的長度保存在一個變量中即可,這樣就不用每次都是計算imgs的長度,改進代碼如下:
1 var length = imgs.length; //把imgs的長度保存在一個變量中 2 for(var i = 0; i <=length; i++) { 3 //執行代碼 4 }
2.盡量使用原生方法
只要有可能,使用原生方法而不是自己用javascript重寫一個。原生方法是用諸如c/c++之類的編譯型語言寫出來的,所以要比JavaScript的快很多很多。
3.使用switch替代if-else
如果有一系列復雜的if-else語句,可以轉化成單個switch語句則可以得到更快的代碼。還可以通過case語句按照最可能的到最不可能的順序進行組織,來進行進一步優化switch語句。
三.最小化語句數
1.多個變量申明,javaScript代碼中的語句數量也影響所執行的操作的速度,完成多個操作的單個語句要比完成單個操作的多個語句快。
1 //四個語句申明變量,浪費! 2 var name = "Bill"; 3 var age = 10; 4 var sex = "man"; 5 6 //一個語句申明變量,干的漂亮! 7 var name = "Bill", 8 age = 10, 9 sex = "man";
2.插入迭代值,當使用迭代值(也就是在不同的位置進行增加或減少的值)的時候,盡可能合並語句。
//兩個語句,浪費! var age = values[i]; i++; //一個語句,干的漂亮! var age = values[i++];
3.使用數組和對象字面量,你可能看過兩種創建數組和對象的方法:使用構造函數或是使用字面量,使用構造函數總是要用到很多語句來插入元素或定義屬性,而字面量可以將這些操作在一個語句中完成。
1 //4個語句創建和初始化數組,浪費! 2 var values = new Array(); 3 values[0] = 123; 4 values[1] = 456; 5 values[2] = 789; 6 7 //4個語句創建和初始化對象,浪費! 8 var person = new Object(); 9 person.name = "Bill"; 10 person.age = 10; 11 person.sayName = function () { 12 console.log(this.name); 13 } 14 15 //1個語句創建和初始化數組,干得漂亮! 16 var values = [123, 456, 789]; 17 18 //一個語句創建和初始化對象,干的漂亮! 19 var person = { 20 name : "bill", 21 age : 10, 22 sayName : function () { 23 console.log(this.name) 24 } 25 }; 26
四.優化DOM交互
1.使用文檔碎片減少DOM交互次數,DOM交互越多,性能越慢。
1 var list = document.getElementById("myList"), 2 item, 3 i; 4 5 for (i = 0; i <= 10; i++) { 6 item.document.createElement("li"); 7 list.appendChild(item); 8 item.appendChild(document.createTextNode(" Item" + i)); 9 }
上面代碼每執行一次for循環都會向DOM插入新的元素,一旦for循環次數很多,那么將嚴重影響代碼性能,所以解決辦法就是減少DOM交互,於是我們使用createDocumentFragment方法創建虛擬節點,把要插入DOM的元素先插入該虛擬節點,循環完之后再把虛擬節點插入DOM,虛擬節點是不會渲染出來的,只會渲染它的子節點。改進代碼如下:
1 var list = document.getElementById("myList"); 2 fragment = document.createDocumentFragment(), 3 i; 4 5 for (i = 0; i < 10; i++) { 6 item = document.createElement("li"); 7 fragment.appendChild(item); 8 item.appendChild(document.createTextNode("Item" + i)); 9 } 10 11 list.appendChild(fragment);
2.使用innerHTML。有兩種在頁面上創建DOM節點的方法:諸如createElement()和appendChild()之類的DOM方法,以及使用innerHTML。當把innerHTML設置為某個值時,后台會創建一個HTML解析器,然后使用內部的DOM調用來創建DOM結構,而非基於JavaScript的DOM調用,由於內部方式是編譯好的而非解釋執行的,所以執行快的多。
3.使用事件委托,把事件綁定在祖先節點,由於有事件冒泡,當事件觸發時根據event對象的target屬性可以知道具體事件是在那個子元素發生的。從而執行不同的行為。這樣就不必每個子節點都綁定事件。