高性能的JavaScriptjavascript
1、 加載和運行java
腳本下載解析執行時,頁面已經加載完成並顯示在用戶面前正則表達式
減小外部腳本文件數量,整合成一個文件算法
非阻塞方式編程
var xhr = new XMLHttpRequest();數組
xhr.open(「get」, 「file.js", true);瀏覽器
xhr.onreadystatechange = function() {緩存
if(xhr.readyState == 4) {閉包
if ….app
var script = document.createElement(「script」);
script.type = 「text/javascript」;
script.text = xhr.responseText;
document.body.appendChild(script);
}
}
優勢:可下載不當即執行的JavaScript代碼
限制:JavaScript文件必須與頁面放置在同一個域內
2、 數據訪問
直接量、變量、數組項、對象成員
每一個JavaScript函數中都有一個僅供JavaScript引擎使用的內部屬性爲[[Scope]]。該屬性包含了函數被建立的做用域鏈中對象的集合。
運行期上下文的做用域鏈中,一個標識符位置越深,它的讀寫速度就越慢。因此,函數中局部變量的訪問速度老是最快的,而全局變量一般是最慢的。
with表達式:做用域鏈前段插入了一個新的對象,局部變量的訪問速度變慢。最好不要用。
try-catch表達式:catch子句執行完畢,做用域鏈返回原來的狀態。
當閉包被運行時,一個運行期上下文將被建立,它的做用域鏈與[[Scope]]中引用的兩個相同的做用域同時被初始化,而後一個新的激活對象爲閉包自身被建立。
腳本中最好當心地使用閉包。
對象成員比直接量和局部變量訪問速度慢,在某些瀏覽器上比訪問數組項還要慢。
因此可能的話避免使用它們,只在必要狀況下使用對象成員。
提升性能:將常用的對象成員,數組項,和域外變量存入局部變量中。而後,訪問局部變量的速度會快於那些原始變量。
3、 DOM編程
DOM操做代價昂貴
三類問題:
l 訪問和修改DOM元素
l 修改DOM元素的樣式,形成重繪和從新排版
l 經過DOM事件處理用戶響應
輕輕地觸摸DOM,並儘可能保持在ECMAScript範圍內。
不標準卻被良好支持innerHTML和純DOM方法如document.createElement()的性能差異不大。舊的瀏覽器上innerHTML快,新瀏覽器上DOM方法更快。
克隆節點更有效率,但提升不太多。
遍歷數組比遍歷集合快。
每次迭代過程訪問集合length屬性,性能低。應將length屬性緩存到一個變量中,而後在循環判斷條件中使用這個變量。
瀏覽器下載完全部頁面HTML標記,JavaScript,CSS,圖片後,它解析文件並建立兩個內部數據
l 一棵DOM樹:表示頁面結構
l 一棵渲染樹:表示DOM節點如何顯示
當佈局和幾何改變時須要重排版:
l 添加或刪除可見的DOM元素
l 元素位置改變
l 元素尺寸改變
l 內容改變
l 最初的頁面渲染
l 瀏覽器窗口改變尺寸
由於代價昂貴,因此好的策略是減小此類操做發生機會。將多個DOM和風格改變合併到一個批次中一次性執行。
l 隱藏元素,進行修改,而後再顯示它。
display = none; 修改;display = block;
l 在已存DOM以外建立一個子樹,而後拷貝到文檔。
createDocumentFragment();append();
l 拷貝原始元素,修改副本,覆蓋原始元素。
cloneNode();replaceChild();
第二種文檔片斷最優
使用如下步驟能夠避免對大部分頁面進行重排版
l 絕對座標定位頁面動畫元素,使它位於頁面佈局流以外
尺寸改變時只會覆蓋其餘元素
l 啓動元素動畫
l 當動畫結束時,從新定位,只一次下移文檔其餘元素位置
事件逐層冒泡總被父元素捕獲;
只需在一個包裝元素上掛接一個句柄,用於處理子元素髮生的全部事件;
DOM標準,每一個事件有三個階段:
捕獲,到達目標,冒泡
10. 總結
爲減小DOM編程中的性能損失,注意如下幾點:
l 最小化DOM訪問,在JavaScript端作儘量多的事情
l 在反覆訪問的地方使用局部變量存放DOM引用
l 當心處理HTML集合,將length屬性緩存到一個變量中
l 使用速度更快的API,如querySelectorAll()和firstElementChild
l 注意重繪和重排版;批量修改風格,離線操做DOM樹,緩存並減小對佈局信息的訪問
l 動畫中使用絕對座標,使用拖放代理
l 使用時間託管技術最小化事件句柄數量
4、 算法和流程控制
代碼總體結構是執行速度的決定因素之一
for-in循環比其餘普通循環明顯要慢;
由於每次迭代操做要搜索實例或原形的屬性。
減小迭代次數;
達夫設備:
var iterations = Math.floor(items.length/8);
startAt = items.length % 8;
i = 0;
do {
switch(startAt) {
case 0 : process(items[i++]);
case 7 : process(items[i++]);
case 6 : process(items[i++]);
case 5 : process(items[i++]);
case 4 : process(items[i++]);
case 3 : process(items[i++]);
case 2 : process(items[i++]);
case 1 : process(items[i++]);
}
startAt = 0;
} while(-- iterations);
forEach()
比基於循環的迭代要慢:每一個數組項要關聯額外的函數調用;
關注執行時間的狀況下它並非一個合適的方法;
大多數狀況下,switch比if-else更快,但只有當條件體數量很大時才明顯;
二者區別:條件體增長時,if-else性能負擔增長程度比switch多;
優化if-else:
條件體應當老是按照從最大機率到最小几率的順序排列,保證理論運行速度更你快;
嵌套使用;
最經常使用於一個鍵和一個值造成邏輯映射領域
遞歸函數會遇到瀏覽器調用棧大小的限制
5、 字符串和正則表達式
「+」,
「+=」,
Array.join(),
String.concat(),
str = str + 「one」 + 「two」;
避免了使用臨時字符串
工做原理:
第一步:編譯
第二步:設置起始位置
第三步:匹配每一個正則表達式的字元
第四步:匹配成功或失敗
6、 響應接口
JavaScript和UI更新共享的進程被稱爲瀏覽器UI進程;
瀏覽器在JavaScript運行時間上採起了限制:
調用棧尺寸限制和長時間腳本限制;
setTimeout()和setInterval()
第二個參數指出是麼時候應當將任務添加到UI隊列之中,並非說那時代碼被執行;
不綁定UI線程,不能訪問許多瀏覽器資源。
7、Ajax異步JavaScript和XML