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