在 上一篇 中,從HTTP請求到頁面渲染幾個方面對提升網站性能提出了幾點建議,本文是學習Steve Sounders
的另一本書《高性能網站建設進階指南》以後,從JavaScript性能的角度進行總結歸納,諸君共勉。html
JavaScript性能
是實現高性能Web應用程序的關鍵
——Steve Sounders編程
當執行一段JavaScript代碼(全局代碼或函數)時,JavaScript引擎會建立爲其建立一個做用域
又稱爲執行上下文
(Execution Context),在頁面加載後會首先建立一個全局的做用域,而後每執行一個函數,會創建一個對應的做用域,從而造成了一條做用域鏈。每一個做用域都有一條對應的做用域鏈,鏈頭是全局做用域,鏈尾是當前函數做用域。數組
做用域鏈的做用是用於解析標識符,當函數被建立時(不是執行),會將this、arguments、命名參數和該函數中的全部局部變量添加到該當前做用域中,當JavaScript須要查找變量X的時候(這個過程稱爲變量解析
),它首先會從做用域鏈中的鏈尾也就是當前做用域進行查找是否有X屬性,若是沒有找到就順着做用域鏈繼續查找,直到查找到鏈頭,也就是全局做用域鏈,仍未找到該變量的話,就認爲這段代碼的做用域鏈上不存在x變量,並拋出一個引用錯誤(ReferenceError)的異常。dom
管理好做用域鏈的深度,是一種只要少許工做就能提升性能的簡易方法,咱們應避免因無心中增加了做用域鏈而致使執行速度變得緩慢。編程語言
若是理解了做用域鏈的概念,那麼咱們應該清楚JavaScript引擎對變量的解析時間跟做用域鏈的深度有關,顯而易見,局部變量因爲處於鏈尾,存取速度是最快的,所以,一個好的經驗是:任何非局部變量使用超過一次時,請使用局部變量將其存儲下來,例如:函數
function changeDiv(){ document.getELementById('myDiv').className = 'changed'; document.getELementById('myDiv').style.height = 150; }
這裏myDiv這個dom元素被引用了兩次,爲了更快的引用,咱們應該用一個局部變量將其存儲下來,這樣作的好處不只縮短了做用域鏈,並且避免了DOM元素的重複查詢:性能
function changeDiv(){ var myDivStyle = document.getElementById('myDiv').style; myDiv.className = 300; myDiv.style.height = 150; }
通常在代碼執行過程當中,函數的做用域鏈是固定的,然而with能夠臨時增加函數的做用域鏈。with用於將對象屬性做爲局部變量來顯示,使其便於訪問,例如:學習
var user = { name:'vicfeel', age:'23' }; function showUser(){ var local = 0; with(user){ console.log("姓名" + name); console.log("年齡" + age); console.log(local); } } showUser();
這個例子中,經過with在showUser做用域鏈的鏈尾中又增長了一個臨時做用域,該做用域存儲着user對象的全部屬性,也就是增加了with這段代碼的做用域鏈,在這段代碼中,局部變量像local從鏈尾的第一個對象變成了第二個,天然減慢了標識符的存取。直到with語句結束,做用域鏈恢復增加。正由於with的這個缺陷,咱們應儘可能避免使用with關鍵字。優化
JavaScript與其它編程語言同樣,擁有一些流控制語句(循環、條件等),在每一個環節上使用恰當的語句能極大的提升腳本的運行速度。網站
提到條件判斷,首先要避免的一種使用方式:
if(value == 0){ return result0; } else if(value == 1){ return result1; } else if(value == 2){ return result2; } else if(value == 3){ return result3; } else if(value == 4){ return result4; } else if(value == 5){ return result5; } else if(value == 6){ return result6; } else{ return result7; }
這種使用if進行條件判斷的方式存在的主要問題是層次太深,當我要value = 7時,消耗時間要比value = 0長不少,大大損耗了性能,同時可讀性不好。
一種更好的方式,利用switch進行判斷。
switch(value){ case 0: return result0; case 1: return result1; case 2: return result2; case 3: return result3; case 4: return result4; case 5: return result5; case 6: return result6; default: return result7; }
這樣不只提升了可讀性,查詢時間也要比if更快。可是若是只有一兩個條件時,if是比switch更快的
在JavaScript中,條件查詢還有另一種方式,以前的例子是根據值返回不一樣的值,恰好能夠利用數組實現hash表的映射查詢。
//定義數組 var results = [result0,result1,result2,result3,result4,result5,result6,result7]; //查詢結果 return results[value];
這種數組的方式,在查詢範圍很大時才更加有效,由於它沒必要檢測上下邊界,只須要填入索引值就能夠查詢了。它的侷限性在於條件對應的是單一值,而不是一系列操做。所以要綜合實際狀況,選擇合適的條件判斷方式,發揮性能最大化。
JavaScript中存在4種循環方式for循環、do-while循環、while循環和for-in循環。下面是一個很經常使用的循環使用方式:
var values = [1,2,3,4,5]; for(var i = 0;i < values.length;i++){ process(values[i]); }
咱們能夠看到,這段代碼最明顯能夠優化的地方在於values.length,每次循環i都要和values的長度進行比較,而查詢屬性要比局部變量更耗時,若是循環次數越大,這種耗時就越明顯,所以能夠這樣優化:
var values = [1,2,3,4,5]; var length = values.length;//局部變量存儲數組長度 for(var i = 0;i < length;i++){ process(values[i]); }
這段代碼還能夠繼續優化,將循環變量遞減到0,而不是遞加到總長度。
var values = [1,2,3,4,5]; var length = values.length; for(var i = length;i--;){ //遞減到0 process(values[i]); }
這裏將循環結束改造爲與0比較,因此每一個循環的速度更快了,根據循環的複雜度不一樣,這種簡單改變能夠比原來節約大概50%的時間。
博文做者:vicfeel
博文出處:http://www.cnblogs.com/vicfeel 本文版權歸做者和博客園共有,歡迎轉載,但須保留此段聲明,並給出原文連接,謝謝合做! 若是閱讀了本文章,以爲有幫助,您能夠爲個人博文點擊「推薦一下」!