因為對DOM的修改為影響網頁的用戶界面,重繪頁面是一項昂貴的操作。太多的JavaScript DOM操作會導致一系列的重繪操作,為了確保執行結果的准確性,所有的修改操作是按順序同步執行的。我們稱這個過程叫做回流(reflow),同時這也是最昂貴的瀏覽器操作之一, 回流操作主要會發生在幾種情況下: 當對DOM節點執行新增或者刪除操作時。 動態設置一個樣式時(比如element.style.width=”10px”)。 當獲取一個必須經過計算的尺寸值時,比如訪問offsetWidth、clientHeight或者其他需要經過計算的CSS值(在兼容DOM的瀏覽器中,可以通過getComputedStyle函數獲取;在IE中,可以通過currentStyle屬性獲取)。
解決問題的關鍵,就是限制通過JavaScript DOM操作所引發回流的次數。大部分瀏覽器都不會在JavaScript的執行過程中更新DOM。相應的,這些瀏覽器將對對DOM的操作放進一個隊列,並在JavaScript腳本執行完畢以后按順序一次執行完畢。也就是說,在JavaScript執行的過程中,用戶不能和瀏覽器進行互動,直到一個回流操作被執行。(失控腳本對話框會觸發回流操作,因為他執行了一個中止JavaScript執行的操作,此時會對用戶界面進行更新) 如果要減少由於DOM修改帶來的回流操作,有兩個基本的方法。第一個就是在對當前DOM進行操作之前,盡可能多的做一些准備工作。一個經典的例子就是向document對象中添加很多DOM節點:
for(var i = 0;i < items.length;i++){ var item=document.createElement("li"); item.appendChild(document.createTextNode("Option"+i); list.appendChild(item); }
這段代碼的效率是很低的,因為他在每次循環中都會修改當前DOM結構。為了提高性能,我們需要將這個次數降到最低,對於這個案例來說,最好的辦法是建立一個文檔碎片(documentfragment),作為那些已創建元素元素的臨時容器,最后一次將容器的內容直接添加到父節點中:
var fragment = document.createDocumentFragment(); for(vari=0;i < items.length;i++){ var item=document.createElement("li"); item.appendChild(document.createTextNode("Option"+i); fragment.appendChild(item); } list.appendChild(fragment);