JavaScript性能優化 DOM編程

JavaScript性能優化 DOM編程css

最近在研讀《高性能JavaScript》,在此作些簡單記錄。示例代碼可在此處查看到。html

1、DOM

1)DOM和JavaScriptgit

文檔對象模型(DOM)是一個獨立於語言的,用於操做XML和HTML文檔的程序接口(API)。正則表達式

瀏覽器一般會把DOM和JavaScript獨立實現。例如Chrome中使用Webkit的WebCore庫渲染頁面,用V8做爲JavaScript引擎。編程

訪問DOM天生就慢,將DOM和JavaScript比喻爲兩個島嶼,兩處同行要收過橋費,ECMAScript訪問DOM的次數越多,過橋費越貴,所以推薦的作法是儘量減小過橋的次數。設計模式

2)性能測試跨域

下圖是對兩段代碼的性能測試,可在此處查看在線性能測試數組

1. 第一段每一次循環都直接用DOM賦值瀏覽器

2. 第二段是先將內容緩存到局部變量中,最後使用一次DOM賦值。緩存

測試結果以每秒鐘執行測試代碼的次數(Ops/sec)顯示,這個數值越大越好。

除了這個結果外,同時會顯示測試過程當中的統計偏差,以及相對最好的慢了多少(%),統計偏差也是很是重要的指標。

2、選擇器API

有時候爲了獲得須要的元素列表,須要組合調用getElementById等並遍歷返回的節點,但這種繁密的過程效率低下。

使用CSS選擇器是一種定位節點的便利途徑,querySelectorAll就是DOM的原生方法。

//DOM組合API
var elements = document.getElementById('menu').getElementsByTagName('a');
//替換爲簡便的CSS選擇器
var elements = document.querySelectorAll('#menu a');

 

3、重繪與重排

在《CSS動畫與JavaScript動畫》中層提到過頁面渲染的通常過程爲JavaScript > 計算樣式 > 佈局 > 繪製 > 渲染層合併。

Layout(重排)和Paint(重繪)是整個環節中最爲耗時的兩環,因此咱們儘可能避免着這兩個環節。

當DOM的變化影響了元素的幾何屬性(寬和高)將會發生重排(reflow);

完成重排後,瀏覽器會從新繪製受影響的部分到屏幕中,此過程爲重繪(repaint)。

1)重排什麼時候發生

1. 添加或刪除可見的DOM元素

2. 元素位置改變

3. 元素尺寸改變(包括外邊距、內邊距、邊框寬度、寬、高等屬性)

4. 內容改變,例如文本改變或圖片被不一樣尺寸的替換掉。

5. 頁面渲染器初始化。

6. 瀏覽器窗口尺寸改變。

2)批量執行重排

下面代碼看上去會重排3次,但其實只會重排1次,大多數瀏覽器經過隊列化修改和批量顯示優化重排版過程。

//渲染樹變化的排隊和刷新
var ele = document.getElementById('myDiv');
ele.style.borderLeft = '1px';
ele.style.borderRight = '2px';
ele.style.padding = '5px';

但下列操做將會強迫隊列刷新並要求全部計劃改變的部分馬上應用:

offsetTop, offsetLeft, offsetWidth, offsetHeight 
scrollTop, scrollLeft, scrollWidth, scrollHeight 
clientTop, clientLeft, clientWidth, clientHeight 
getComputedStyle() (currentStyle in IE)(在 IE 中此函數稱爲 currentStyle) 

像offsetHeight屬性須要返回最新的佈局信息,所以瀏覽器不得不執行渲染隊列中的「待處理變化」並觸發重排以返回正確的值。

對於尺寸座標相關的信息能夠參考《JavaScript中尺寸、座標》。

3)最小化重繪和重排

1. cssText和class

cssText能夠一次設置多個CSS屬性。class也能夠一次性設置,而且更清晰,更易於維護,但有前提條件,就是不依賴於運行邏輯和計算的狀況。

// cssText
ele.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;';
// class
ele.className = 'active';

在《JavaScript特性(attribute)、屬性(property)和樣式(style)》詳細介紹了CSS相關的JS操做。

2. 批量修改DOM

2.1 隱藏元素display:none,應用修改,從新顯示display:block

2.2 使用文檔片斷fragment,在片斷上操做節點,再拷貝迴文檔。

//文檔片斷(fragment)
var fragment = document.createDocumentFragment();
var li = document.createElement('li');
li.innerHTML = 'banana';
fragment.appendChild(li);
document.getElementById('fruit').appendChild(fragment);

2.3 將原始元素拷貝到一個脫離文檔的節點中(例如position:absolute),修改副本,完成後再替換原始元素。

 

4、其它章節性能介紹

1)第一章 加載和執行

將<script>標籤放到頁面底部,也就是</body>閉合標籤以前。

多種無阻塞下載JavaScript的方法:

1. 使用<script>標籤的defer屬性。頁面解析到<script>標籤時開始下載,但並不會執行,直到DOM加載完(onload事件觸發前)。

2. 動態建立<script>元素來下載並執行代碼。不管在什麼時候啓動下載,文件的下載和執行過程不會阻塞頁面其它進程,但返回的代碼一般會馬上執行。

3. 使用XHR對象下載JavaScript代碼並注入頁面中。優勢是下載後不會自動執行,全部主流瀏覽器都支持,但不能跨域下載。

2)第二章 數據存取

1. 每遇到一個變量,就會經歷一次標識符解析的過程,以決定在哪裏獲取和存儲數據。在執行環境的做用域中,標識符所在的位置越深,讀寫速度也就越慢。所以函數中讀寫局部變量是最快的,讀寫全局變量是最慢的。

2. 因爲對象成員可能包含其它成員,例如window.location.href。每次遇到點操做符,嵌套成員會致使JavaScript引擎搜索所有對象成員。對象成員嵌套越深,讀取速度越慢location.href就比window.location.href快。

3)第五章 字符串與正則表達式

str = str + "one";//性能高
str = "one" + str;//性能差

1. 除IE外,瀏覽器會簡單的將第二個字符串拷貝到第一個的後面,若是變量str很大的話,就會出現性能損耗(內存佔用)就會很高。

2. 正則優化包括:減小分支數量,縮小分支範圍;使用非捕獲數組;只捕獲感興趣的文本以減小後期處理;使用合適的量詞;化繁爲簡,分解複雜的正則;

4)第六章 快速響應的用戶界面

使用定時器讓出時間片斷,分割大型任務,在文章《JavaScript定時器分析》中有具體分析。

5)第七章 Ajax

Mutipart XHR容許客戶端只用一個HTTP請求就能夠從服務器向客戶端傳送多個資源。

將資源文件(CSS、HTML、JavaScript、Base64編碼圖片)打包成一個由雙方約定的字符串分隔符,發送到客戶端。

而後用JavaScript代碼處理這個字符串,根據「mime-type」類型和傳入的頭信息解析每一個資源。

6)第九章 構建並部署高性能JavaScript應用

1. 合併JavaScript文件以減小HTTP請求數。

2. 壓縮JavaScript文件。

3. 在服務器端壓縮JavaScript文件(Gzip編碼)。

4. 正確設置HTTP響應頭來緩存JavaScript文件,經過向文件名增長時間戳避免緩存問題。

5. 使用CDN(Content Delivery Network)提供JavaScript文件。

第八章 編程實踐內容比較多,單獨令出來做爲一節。

 

5、第八章 編程實踐

1)使用Object/Array直接量

代碼例下:

var myObject = { 
  name: "pwstrick", 
  age: 29 
};
var myArr = ["pwstrick", 29];

2)避免重複工做

也就是惰性模式。減小每次代碼執行時的重複性分支判斷,經過對對象重定義來屏蔽原對象中的分支判斷。

惰性模式分爲兩種:第一種文件加載後當即執行對象方法來重定義,第二種是當第一次使用方法對象時來重定義。可參考在線demo代碼

在文章《JavaScript設計模式》中有更多的設計模式介紹。

3)位運算

1. 用位運算取代純數學操做,好比對2取模digit%2能夠判斷偶數與奇數。

2. 位掩碼技術,使用單個數字的每一位來判斷選項是否成立。掩碼中每一個選項的值都是2的冪。例如:

var OPTION_A = 1, OPTION_B = 2, OPTION_C = 4, OPTION_D = 8, OPTION_E = 16;
//用按位或運算建立一個數字來包含多個設置選項
var options = OPTION_A | OPTION_C | OPTION_D;
//接下來能夠用按位與操做來判斷給定的選項是否可用
//選項A是否在列表中
if(options & OPTION_A) {
  //...
}

3. 用按位左移(<<)作乘法,用按位右移作除法(>>),例如digit*2能夠替換成digit<<2

4)原生方法

不管你的代碼如何優化,都比不上JavaScript引擎提供的原生方法快。

1. 數學運算用內置的Math對象中提供的方法。

2. 用原生的CSS選擇器查找DOM節點,querySelectorquerySelectorAll

相關文章
相關標籤/搜索