JavaScript效能最佳化 DOM編程

來源:互聯網
上載者:User

標籤:java

一、DOM

1)DOM和JavaScript

文件物件模型(DOM)是一個獨立於語言的,用於操作XML和HTML文檔的程式介面(API)。

瀏覽器通常會把DOM和JavaScript獨立實現。例如Chrome中使用Webkit的WebCore庫渲染頁面,用V8作為JavaScript引擎。

訪問DOM天生就慢,將DOM和JavaScript比喻為兩個島嶼,兩處同行要收過橋費,ECMAScript訪問DOM的次數越多,過橋費越貴,因此推薦的做法是儘可能減少過橋的次數。

650) this.width=650;" src="http://images2015.cnblogs.com/blog/211606/201704/211606-20170426170502459-68141551.png" width="400" style="border:0px;margin-top:0px;" />

2)效能測試

是對兩段代碼的效能測試,可在此處查看線上效能測試。

1. 第一段每一次迴圈都直接用DOM賦值

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

650) this.width=650;" src="http://images2015.cnblogs.com/blog/211606/201704/211606-20170426172643365-1912134911.png" width="600" style="border:0px;margin-top:0px;" />

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

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

二、選取器API

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

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

//DOM組合APIvar elements = document.getElementById(‘menu‘).getElementsByTagName(‘a‘);//替換為簡便的CSS選取器var elements = document.querySelectorAll(‘#menu a‘);

上面的例子不能體現效率的區別, 後面又改寫了一個。在codepen中書寫了一個例子,可以線上查看。

//從列表中選出CSS類是one的節點var elements = document.querySelectorAll(‘#menu a.one‘);var elements = document.getElementById(‘menu‘).getElementsByTagName(‘a‘), list=[];for(var i=0, len=elements.length; i<len; i++) {  if(elements[i].className == ‘one‘) {      list.push(elements[i]);    }}

 

 

三、重繪與重排

在《CSS動畫與JavaScript動畫》中層提到過頁面渲染的一般過程為JavaScript > 計算樣式 > 布局 > 繪製 > 渲染層合并。

650) this.width=650;" src="http://images2015.cnblogs.com/blog/211606/201612/211606-20161229145018554-642695777.png" width="600" style="border:0px;margin-top:0px;" />

Layout(重排)和Paint(重繪)是整個環節中最為耗時的兩環,所以我們盡量避免著這兩個環節。

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

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

1)重排何時發生

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

2. 元素位置改變

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

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

5. 頁面渲染器初始化。

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

2)批量執行重排

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

650) this.width=650;" src="http://images2015.cnblogs.com/blog/211606/201704/211606-20170427101750912-520139977.png" width="300" style="border:1px solid rgb(204,204,204);margin-top:0px;" />

//渲染樹變化的排隊和重新整理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也可以一次性設定,並且更清晰,更易於維護,但有前提條件,就是不依賴於運行邏輯和計算的情況。

// cssTextele.style.cssText = ‘border-left: 1px; border-right: 2px; padding: 5px;‘;// classele.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),修改副本,完成後再替換原始元素。

 

四、其它章節效能介紹

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)第五章 字串與Regex

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檔案。

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

 

五、第八章 編程實踐

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節點,querySelector或querySelectorAll。


JavaScript效能最佳化 DOM編程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.