本文基於《高性能JavaScript》整理而成。javascript
<script>
標籤引用的外部js
文件,仍是內聯的<script>
標籤,都會阻塞其餘瀏覽器的處理過程,直到js
代碼被「下載--解析--執行」完成後,纔會繼續其餘進程。js
文件,但瀏覽器進程仍然須要等待全部js
文件執行完畢後,纔會繼續。<script>
標籤不會阻塞頁面的解析。<body>
前,頁面是空白的。<script>
標籤放置在頁面的底部,僅靠</body>
的上方。此方法能夠保證頁面在腳本運行前完成解析。將腳本成組打包。css
頁面的<script>
標籤越少,頁面的加載速度越快,響應也更加迅速。不論外部腳本文件仍是內聯代碼都是如此。爲<script>
標籤添加defer
屬性(只適用於IE
和Firefox 3.5
以上的版本)html
js
代碼會在domReady
後執行動態建立<scirpt>
元素,用它下載並執行代碼java
<script>
不會阻塞頁面的解析,js
代碼的處理和頁面的解析是並行的用ajax
下載代碼,注入頁面中ajax
ajax
方式的缺點是不能跨域獲取js
代碼算法
函數對象編程
建立函數時,會建立一個函數對象,並建立一個做用域鏈(內部[[scope]]屬性
)json
每執行一次函數,就建立一個運行上下文windows
運行上下文也會建立一個做用域鏈,並將函數對象的做用域鏈賦值到運行上下文,再新建一個活動對象,置於做用域鏈的第一個位置。跨域
做用域鏈:做用域鏈銷燬時,活動對象額一同銷燬
with
with
表達式時,運行期上下文的做用域鏈被臨時改變。一個新的可變對象被建立,它包含指定對象的全部屬性,此對象被推入做用域鏈的簽到,意味着如今函數的全部局部變量被推入第二個做用域鏈對象中,全部訪問代價更高try catch
catch
塊中,會將異常對象推入做用域鏈簽到的一個可變對象中catch
執行完畢,做用域鏈會返回到原來的狀態with
謹慎使用try catch
能夠精簡代碼最小化catch
對性能的影響,一個很好的模式是將錯誤交給一個專用函數來處理。沒有局部變量訪問,做用域鏈臨時改變不會影響代碼的性能。
背景
優化的JS引擎是經過分析靜態代碼來肯定哪些變量應該在任意時刻被訪問,企圖避開傳統的做用域鏈查找,取代以標識符索引的方式進行快速查找。當涉及一個動態做用域後,此優化方法就不起做用了。引發須要切回慢速的寄語哈希表的標識符識別方法,更像傳統的做用域鏈搜索IE
中更被關注,IE使用非本地JS
對象實現DOM
對象,閉包可能致使內存泄露hasOwnProperty()
訪問的是實例成員in
訪問的是實例+原型成員with
表達式,由於它該變量運行期上下文的做用域鏈。try-catch
表達式的catch
語句,由於它有一樣的效果通常來講,能夠經過如下方法提升性能:
將常常用到的對象成員,數組項和域外變量存入局部變量中,而後,訪問局部變量的速度會快於那些原始變量
JavaScript
實現的JavaScript
實現保持相互獨立
IE
中
JavaScript
實現:位於庫jscript.dll
中DOM
實現:位於另外一個庫mshtml.dll(內部代號Trident)
中Safari
中
JavaScript
實現:JavaScriptCore
引擎DOM
實現:Webkit
的WebCore
處理Chrome
中
JavaScript
實現:V8
引擎DOM
實現:Webkit
的WebCore
處理Firefox
中
JavaScript
實現:TraceMonkey
引擎DOM
實現:Gecko
渲染引擎innerHTML
與DOM
方法對比
innerHTML
不是標準的,但被支持的很好DOM
方法有:document.createElement()
等innerHTML
速度更快,除了最新的基於WebKit
的瀏覽器element.cloneNode()
)
HTML
集合
document.getElementsByTagName()
得到的元素集length
屬性,但不是數組length
屬性上length
childNodes
nextSibling
IE
中,nextSibling
的效率更高,其餘狀況下,沒太多差異childNodes
、firstChild
、nextSibling
也會返回註釋節點和文本節點,所以每次使用都要判斷節點類型,比較麻煩children
)
children
替代childNodes
,children
更快,由於集合項更少childElementCount
替代childNodes.length
firstElementChild
替代firstChild
lastElementChild
替代lastChild
nextElementSibling
替代nextSibling
previousElementSibling
替代previousSibling
document.querySelectorAll()
:hover
:hover
for
while
do while
js
中惟一一種後測試的循環,包括:循環體和後測試條件for in
for in
速度最慢,由於它要查找各類屬性
優化
若是要迭代一個有限的、已知的屬性列表,使用其餘循環類型更快,可以使用以下模式(只關注感興趣的屬性):
var props = ["prop1", "prop2"], i = 0; while (i < props.length){ process(object[props[i]]); }
foreach
每次迭代都會調用函數,性能較低if else
switch
switch
。switch
更快if else
if else
組織成一系列嵌套的if else
表達式。使用一個單獨的一長串的if else
一般致使運行緩慢,由於每一個條件都要被計算
JavaScript
的運行時間。與其餘語言不一樣的是,JavaScript
可用資源有限,因此優化技術更爲重要for
、while
、do-while
循環的性能特性類似for-in
循環switch
老是比if-else
更快,但並不老是最好的解決辦法if-else
或者switch
更快JavaScript
中的應用:棧溢出錯誤致使其餘代碼也不能正常執行JavaScript
任務JavaScript
代碼運行時用戶界面不能對輸入產生反應,反之亦然。管理好JS
運行時間對網頁應用的性能很重要JS
和UI
更新共享的進程一般被稱做瀏覽器UI線程。JS
代碼,就是執行UI更新,包括重繪和排版JS
操做應當使用的總時間(最大)是100毫秒JS
任務由於複雜性緣由不能在100毫秒或更少的時間內完成,這種狀況下,理想方法是讓出對UI線程的控制,讓UI更新能夠進行,讓出控制意味着中止JS
運行,給UI線程機會進行更新,而後再運行`JSsetTimeout
到達時間後,只是加入隊列,並非執行do-while
循環)JavaScript
和用戶界面更新在同一個進程內運行,同一時刻只有其中一個能夠運行。有效地管理UI線程就是要確保JavaScript
不能運行太長時間,一面影響用戶體驗。所以要注意:
JavaScript
運行時間不該該超過100毫秒,過長的運行時間致使UI更新出現可察覺的延遲,從而對總體用戶體驗產生負面影響JavaScript
運行期間,瀏覽器響應用戶交互的行爲存在差別,不管如何,JavaScript
長時間運行將致使用戶體驗混亂和脫節JavaScript
代碼而避免鎖定UIJavaScript
代碼能夠重要到容許影響用戶體驗的程度XMLHttpRequest(XHR)
(經常使用)動態腳本標籤插入
(經常使用)Multipart XHR
(經常使用)iframes
(不經常使用)Comet
(不經常使用)XHR
ajax
GET
或POST
GET
GET
GET
請求會被緩存POST
POST
提取數據jsonp
)
GET
方法傳遞,不能用POST
Multipart XHR
XHR
XHR
主要用於從服務器獲取數據,它也能夠用來向服務器發送數據GET
和POST
方式發送數據,以及任意數量的HTTP信息頭。這樣靈活性大。當數據量超過瀏覽器的最大URL長度時,XHR
特別有用。這時候能夠用POST
方式發送數據GET
比POST
快。
GET
請求要佔用一個單獨的數據包POST
至少要發送兩個數據包,一個用於信息頭,一個是POST體Image
對象,將src設置爲服務器上一個腳本文件的URLImage
對象沒必要插入DOM節點POST
數據onload
,不多能獲取服務器返回的信息JSON
和字符分隔的自定義格式。數據量大的話,就用這兩種格式Ajax
請求
HTTP
頭,確保返回報文被緩存在瀏覽器中Ajax
響應報文,客戶端發起請求必須使用GET
方法Expires
頭Ajax
包括:知道你項目的具體需求,選擇正確的數據格式和與之相配的傳輸技術XHR
提供最完善的控制和靈活性,儘管它將全部傳入數據視爲一個字符串,這有可能下降解析速度jsonp
容許跨域,但接口不夠安全,並且不能讀取信息頭或響應報文代碼MXHR
能夠減小請求的數量,一次響應中處理不一樣的文件類型,儘管它不能緩存收到的響應報文XHR
也能夠用POST
方法發送大量數據Ajax
的速度
JavaScript
和CSS
打包,或者使用MXHR
Ajax
獲取少許重要文件Ajax
庫,什麼時候編寫本身的底層Ajax
代碼Ajax
是提高網站性能的最大的改進區域之一JavaScript
容許在程序中獲取一個包含代碼的字符串而後運行它eval_r()
Function()
構造器setTimeout()
setInterval()
Math
屬性
Math.E
Math.LN10
Math.LN2
Math.LOG2E
Math.LOG10E
Math.PI
Math.SQRT1_2
Math.SQRT2
Math
方法
Math.abs(num)
Math.exp(num)
Math.log(num)
Math.pow(num, power)
Math.sqrt(num)
Math.acos(x)
Math.asin(x)
Math.atan(x)
Math.atan2(y, x)
Math.cos(x)
Math.sin(x)
Math.tan(x)
querySelector()
querySelectorAll()
eval_r()
和Function()
構造器避免二次評估,此外,給setTimeout()
和setInterval()
傳遞函數參數而不是字符串參數JavaScript
寫的東西要快。儘可能使用原生方法。JavaScript
文件,減小HTTP
請求的數量JS
文件JS
文件可緩存,經過向文件名附加時間戳解決緩存問題JS
文件,CDN不只能夠提升性能,還能夠爲你管理壓縮和緩存