DOM優化

1. 批量增加 Dom

儘量使用修改 innerHTML 的方式而不是用 appendChild 的方式 ; 因爲使用 innerHTML 開銷更小 , 速度更快 , 同時也更加內存安全 .

有一點需要注意的是 , 用 innerHTML 方式添加時 , 一定不要在循環中使用 innerHTML += 的方式添加 , 這樣反而會使速度減慢 ; 而是應該中間用 array 緩存起來 , 循環結束後調用 xx.innerHTML = array.join(‘’); 的方式 , 或者至少保存到 string 中再插到 innerHTML 中 .

針對用戶列表一塊採用這種方式優化後 , 加載速度提升一倍 .

2. 單個增加 Dom

這裏是指要將新節點加載到一個內容不斷變化的節點的情形 , 對於內容穩定的節點來說 , 隨便怎麼加都沒有問題 .但是對於有動態內容的節點來說 , 爲其添加子節點儘量使用 dom append 的方式 .

這是因爲 ,dom append 不會影響到其他的節點 ; 而如果修改 innerHTML 屬性的話 , 該父節點的所有子節點都會從 dom 樹中剝離 , 再根據新的 innerHTML 值來重繪子節點 dom 樹 ; 所有註冊到原來子節點的事件也會失效 .

綜上 , 如果在一個有動態內容的節點上 出現了 innerHTML += 的代碼 , 就該考慮是否有問題了 .

3. 創建 Dom 節點

用 createElement 方式創建一個 dom 節點 , 有一個很重要的細節 : 在執行完 createElement 代碼之後 , 應該馬上append 到 dom 樹中 ; 否則 , 如果在將這個孤立節點加載到 dom 樹之前所做的賦值它的屬性和 innerHTML 的操作都會引發該 dom 片段內存無法回收的問題 . 這個不起眼細節 , 一旦遇到大量 dom 增刪操作 , 就會引發內存的災難 .

4. 刪除 Dom 節點

刪除 dom 節點之前 , 一定要刪除註冊在該節點上的事件 , 不管是用 observe 方式還是用 attachEvent 方式註冊的事件 , 否則將會產生無法回收的內存 .

另 , 在 removeChild 和 innerHTML=’’ 二者之間 , 儘量選擇後者 . 因爲在 sIEve( 內存泄露監測工具 ) 中監測的結果是用 removeChild 無法有效地釋放 dom 節點 .

5. 創建事件監聽

現有的 js 庫都採用 observe 方式來創建事件監聽 , 其實現上隔離了 dom 對象和事件處理函數之間的循環引用 ,所以應該儘量採用這種方式來創建事件監聽 .

6. 監聽動態元素

Dom 事件默認是向上冒泡的 , 發生在子節點中的事件 , 可以由父節點來處理 . Event 的 target/srcElement 仍是產生事件的最深層子節點 . 這樣 , 對於內容動態增加並且子節點都需要相同的事件處理函數的情況 , 可以把事件註冊上提到父節點上 , 這樣就不需要爲每個子節點註冊事件監聽了 .

同時 , 這樣做也避免了產生無法回收的內存 . 即使是用 Prototype 的 observe 方式註冊事件並在刪除節點前調用stopObserving, 也會產生出少量無法回收的內存 , 所以應該儘量少的爲 dom 節點註冊事件監聽 .

所以 , 當代碼中出現在循環裏註冊事件時 , 也是我們該考慮事件上提機制的時候了 .

7. HTML 提純

HTML 提純體現的是一種各負其責的思想 . HTML 只用來顯示 , 儘量不出現和顯示無關的屬性 . 比如 onclick 事件 , 比如自定義的對象屬性 .

事件可以用前面的方法避免 , 對象屬性指的是這樣的一種情景 : 通常情況下 , 動態增加的內容都是有個對象和它對應 ,比如聊天室的用戶列表 , 每個顯示用戶的 dom 節點都有一個 user 對象和它對應 , 這樣在 html 中 , 應該僅保留一個 id屬性和 user 對象對應 , 而其他的信息 , 則應通過 user 對象去獲取 .


    基於 PrototypeJS ,寫了一個 Dom 生成器,以提供簡單高效的 HTML 操作接口的語法和語義優化 

1. 使用類似 JSONML 的格式 (HTML in JSON) 描述 DOM 結構,以補充 HTML 轉義字符串的表達形式,規範格式中可支持以下 HTML 語義:

l 標籤名

l 屬性 ( 標識符 , 類名 , 事件名 , 內聯樣式等 )

注:事件名上註冊的偵聽函數將自動通過 Event.observe 方式添加

l 嵌套標籤

格式規範可簡單描述爲:

{

tag:string,  // 元素的標記名,如果沒有,默認爲 div

children|cn: string|Array|json,  // 子結點對應的 json 數組或字節點的 html 或單個 json

html:string,  // 對應的 html ,如果有 cn  children 屬性就忽略

style:function|string|json,  // 元素的樣式,可以是函數,字符串, json 對象

cls:string,  // 元素的 class 屬性的值

x:y  // x 表示其他名字, y 表示變量值、非空字符串

onXXX: function //  on 爲首的屬性是事件偵聽器

}

一個具體的例子爲:

var list = DomBuilder.append( 'my-div' , {

tag : 'ul' ,

cls : 'my-list' ,

children : [

{

tag : 'li' ,

id : 'item1' ,

html : 'List Item 1' ,

onclick : function () {

alert( 'List Item1 Clicked' )

}

},

{

tag : 'li' ,

id : 'item2' ,

html : 'List Item 2' ,

customattr : 'customValue'

}]

});

2. 在實際修改 DOM 結構時,提供兩種方式可供調用者選擇,以便應需使用:

l W3C 標準 DOM 操作 (appendChild, removeChild) 方式

l 使用 innerHTML,insertAdjacentHTML 等的實效模式

一個具體例子爲:

DomBuilder.useDom = true ; // 顯示申明使用 W3C Dom 操作方式

3. 另外提供 DOM 節點的有效回收方法

var abandoned = DomBuilder.destroy(list); //  DOM 節點從文檔中移除


From:http://www.360doc.com/content/11/0423/12/49999_111730957.shtml

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章