隨著計算機硬體的不斷升級,開發者越發覺得Javascript
效能優化的好不好對網頁的執行效率影響不明顯,所以一些效能方面的知識被很多開發者忽視。但在某些情況下,不優化的Javascript
程式碼必然會影響使用者的體驗。因此,即使在當前硬體效能已經大大提升的時代,在編寫Javascript
程式碼時,若能遵循Javascript
規範和注意一些效能方面的知識,對於提升程式碼的可維護性和優化效能將大有好處。那麼,接下來我們討論幾種能夠提高JavaScript效能
的方法。
1、js檔案載入和執行
<script>
標籤放到<body>
標籤的底部js
檔案,減少頁面中<script>
標籤改善效能defer
屬性,載入後續文件元素的過程將和 script.js
的載入並行進行,但是 script.js
的執行要在所有元素解析完成之後,DOMContentLoaded
事件觸發之前完成。async
屬性,載入和渲染後續文件元素的過程將和 script.js
的載入與執行並行進行var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'file.js';
document.getElementsByTagName('head')[0].appendChild(script);複製程式碼
2、識別符號所在的作用域鏈的位置越深
識別符號所在的作用域鏈的位置越深,那麼它的識別符號解析的效能就越慢。所以一個好的效能提升的經驗法則是:如果某個跨作用域的值在函式中被引用一次以上,那麼就把它儲存到區域性變數裡。
function fun1() {
// 將全域性變數的引用先儲存在一個區域性變數中,然後使用這個區域性變數代替全域性變數,從而提高
// 效能;不然每次(3次)都要遍歷整個作用域鏈找到
document var doc = document;
var bd = doc.body;
var links = doc.getElementsByTagName('a');
doc.getElementById('btn').onclick = function(){
console.log('btn');
}
}複製程式碼
3、避免過長原型鏈繼承
方法或屬性在原型鏈中存在的位置越深,搜尋它的效能也就越慢,所以要避免N多層原型鏈的寫法。
4、物件成員巢狀過深
物件的巢狀成員,物件成員巢狀越深,讀取速度也就越慢。所以好的經驗法則是:如果在函式中需要多次讀取一個物件屬性,最佳做法是將該屬性值儲存在區域性變數中,避免多次查詢帶來的效能開銷。
function f() {
// 因為在以下函式中需要3次用到DOM物件屬性,所以先將它儲存在一個區域性變數
// 中,然後使用這個區域性變數代替它進行後續操作,從而提高效能
var dom = YaHOO.util.Dom;
if(Dom.hasClass(element,'selected')){
Dom.removeClass(elemet,'selected');
}else{
Dom.addClass(elemet,'selected');
}
}複製程式碼
5、DOM操作
用js
訪問和操作DOM
都會帶來效能損失,可通過以下幾點來減少效能損失:
DOM
訪問次數;DOM
節點,請使用區域性變數儲存它的引用;HTML
集合,因為它實時連繫著底層文件;我們可以把集合的長度快取到一個變數中,並在迭代中使用它;- 新增或刪除可見的
DOM
元素; - 元素位置改變;
- 元素尺寸改變(包括:外邊距、內邊距、邊框厚度、寬度、高度等屬性);
- 內容改變(例如:文字改變或圖片被另一個不同尺寸的圖片改變);
- 頁面渲染器初始化;
- 瀏覽器視窗尺寸改變
- 留意上面會導致重排的操作,儘量避免;
- 獲取佈局資訊的操作會導致強制渲染佇列重排,應該儘量避免使用以下獲取佈局資訊的操作方法或屬性或者快取佈局資訊,例如:
offsetTop,offsetLeft,offsetWidthoffsetHeight,
scrollTop,scrollLeft,scrollWidth,scrollHeight,clientTop,clientLeft,clientWidth,clientHeight,getComputedStyle()
等; - 批量修改樣式,例如使用:
function f() {
// 推薦使用以下操作
var el1 = document.getElementById('mydiv');
el1.style.cssText = 'border:1px;padding:2px;margin:3px';
// 不推薦使用以下操作
var el2 = document.getElementById('mydiv');
el2.style.border = '1px';
el2.style.padding = '2px';
el2.style.margin = '3px';
}複製程式碼
- 當需要批量修改
DOM
時,可以通過以下步驟減少重繪和重排的次數: - 使元素脫離文件流(隱藏元素、拷貝元素)
- 對其應用多重改變;
- 把元素帶回文件中
- 使用事件委託(事件逐層冒泡並能被父級元素捕獲,使用事件代理,只需給外層元素繫結一個處理器,就可以處理其子元素上觸發的所用事件),因為給
DOM
元素繫結事件以及瀏覽器需要跟蹤每個事件處理器都需要消耗效能。
6、字串連線
str += 'one'+'two';
str= str+'one'+'two';複製程式碼
7、直接使用字面量
建立物件和陣列推薦使用字面量,因為這不僅是效能最優也有助於節省程式碼量。
var obj = {
name:'tom',
age:15,
sex:'男'
}複製程式碼
8、陣列長度快取
如果需要遍歷陣列,應該先快取陣列長度,將陣列長度放入區域性變數中,避免多次查詢陣列長度。
9、迴圈比較
JS
提供了三種迴圈:for(;;)、while()、for(in)
。在這三種迴圈中 for(in)
的效率最差,因為它需要查詢Hash鍵,因此應儘量少用for(in)
迴圈,for(;;)、while()
迴圈的效能基本持平。
10、少用eval
儘量少使用eval
,每次使用eval
需要消耗大量時間,這時候使用JS
所支援的閉包可以實現函式模板。
11、字串轉換
當需要將數字轉換成字元時,採用如下方式:"" + 1
。從效能上來看,將數字轉換成字元時,有如下公式:("" +) > String() > .toString() > new String()
。String()
屬於內部函式,所以速度很快。而.toString()
要查詢原型中的函式,所以速度遜色一些,new String()
需要重新建立一個字串物件,速度最慢。
12、浮點數轉換整形
當需要將浮點數轉換成整型時,應該使用Math.floor()
或者Math.round()
。而不是使用parseInt()
,該方法用於將字串轉換成數字。而且Math
是內部物件,所以Math.floor()
其實並沒有多少查詢方法和呼叫時間,速度是最快的。