在使用dom操作時,同樣的效果
用不同的方式來實現
,效能方面也會有很大的差異。尤其在移動式裝置上,資源本來就很有限,一旦dom寫不好的話操作就會非常卡頓。這個週末,就寫個dom效能小記吧。錯漏之處,望多指教。
1、淺說reflow
首先講講最近我才了解到的乙個比較深入且模糊的東西——reflow。
從字面上理解的話,reflow有回流、重排的意思。它是指在dom內容更新或增刪時發生的乙個響應過程,可以理解為頁面內容改變了,然後發生重新排版這樣的乙個行為。
我們可以將執行dom操作細分為以下三個過程:讀取html內容——>頁面reflow——>展示更新內容。
由於reflow是乙個重整布局和樣式的過程,相當消耗效能。所以我們優化dom效能實際上就是避免執行更多dom操作,即減少reflow過程。
2、減少reflow常用方法
採用臨時變數儲存,一次性操作dom
以我筆記本為例,分別測試了以下兩段**:
1//**1
2 window.onload = function()7
}8//**2
9 window.onload = function
()15 oul.innerhtml =str;
16 }
t/ms
1
2
3
4
5
6
7
8
9
10
**1
9067.696
8900.826
9114.520
8987.592
9220.753
9344.496
8783.459
8797.731
9337.738
8835.503
**2
4.100
1.883
2.177
2.262
2.416
5.464
2.053
1.891
2.053
1.975
從上面資料明顯看得出,同樣執行10000次拼接,**二遠快於**一。
不難得出結論:減少dom訪問,改用外部變數臨時儲存內容,最後再一步執行dom操作的效率遠高於分次執行dom操作。
**二的速度約是**一的4000倍,可粗略計算出,innerhtml每查詢並賦值一次,用時就接近1ms。
採用class修改多個樣式,一次性更改屬性
分別測試以下**:
1//**三
2 window.onload = function
()else18}
19}2021
//**四
22 window.onload = function
()else30}
31 }
同樣在chrome瀏覽器下測試執行用時如下,前五次為兩段**分開執行,後五次為兩段**放一起執行(排除電腦不同時間點執行的差異):
t/ms
1
2
3
4
5
6
7
8
9
10
**3
346.540
471.160
322.437
327.363
335.818
283.553
346.819
318.261
313.144
333.789
**4
38.666
20.042
19.550
26.465
27.294
38.429
33.793
37.031
34.928
36.221
從上面的資料可以看出,通過設定class改變多個樣式的方法比分次改變樣式明顯快得多。
在不考慮js**賦值運算增多帶來了誤差的情況下(實際上很小),**4的方法平均耗時也比**3的方法快10多倍。因為在**3中,我每改變乙個樣式都會產生一次reflow,即reflow了5次。而在**四中使用classname卻只reflow了一次,但一次reflow改變了多個樣式。
這裡需要注意的是,不是所有樣式的改變都會產生reflow的。只有會影響布局的樣式才會,例如width,height,display,line-height,margin,padding,font,background等等。諸如color,opacity,visibility等則不會,因為它們只會產生repaint。你可以想象得到,改變顏色、透明度等值對頁面的結構是不會產生任何影響的。這裡我就不展開講了。
採用變數儲存節點屬性值,減少獲取次數
測試**:
1//**5
2for (var i = 0; i < 10000; i++) else
8}910
//**6
11var u1 = document.getelementbyid('ul1');
12var uw =u1.offsetheight;
13for (var i = 0; i < 10000; i++) else
19 }
分別執行以上**10000次的10個時間樣本對比:
t/ms
1
2
3
4
5
6
7
8
9
10
**5
1256.209
1175.189
1384.690
1241.207
1223.094
1371.524
1186.556
1176.889
1269.450
1215.922
**6
20.633
14.353
17.901
19.665
31.405
20.503
24.451
18.909
23.883
14.472
同樣可以看出,**6是明顯比**5執行速度快的。
當我們知道某乙個節點的某些屬性值是確定時,這時候我們可以將這個值儲存在變數中,而不需要每次重新獲取。否則當執行次數達到一定量後,會嚴重影響程式執行的速度。因為當第一次使用變數獲取某個節點的值時,頁面就會只reflow一次,並把這個值儲存在記憶體中。下次程式需要時從記憶體中取就可以了。而**5中則每次都沿著document去讀取這些值,這些值雖然沒有改變,但這些值是瀏覽器需要計算才能獲得的,所以每次都會reflow一次。
會導致reflow的屬性有offsetleft/top、offsetheight/width、scrolltop/left/width/height、clienttop/left/width/height等。
養成使用這種方法的
習慣,不但能提高程式效能,有時候還可以節省**量,使程式更簡潔。
JS 效能優化小記
js語法層面的效能優化 先看乙個2萬次的遍歷性能開銷圖 chrome 版本 83.0.4103.61 正式版本 64 位 發現了什麼?同樣是foreach 執行效率截然不同,所以不能簡單的對比 for for.of foreach 效能上的差異,理所當然的認為效能開銷所差無幾,建議使用for 迴圈 ...
如何寫出高效能DOM?
提高高效能dom就不得不提到回流和重繪,那麼什麼是回流什麼是重繪?回流 對於dom結構中的各個元素都有自己的盒子模型,這些都需要瀏覽器根據各種樣式 瀏覽器的 開發人員定義的 來計算並根據計算結果將元素放到它該出現的位置,這個過程稱為回流。重繪 當各種盒子的位置 大小以及其他屬性,例如顏色 字型大小等...
KDB和Oracle的效能pk小記
在偶然的機會聽到了kdb,然後帶著好奇和新鮮感體驗了一把這個傳說中和oracle 相似度達到99 的資料庫。其中一部分的驅動力在於這個活動的獎品很豐厚,參加活動後可以拿到乙個iwatch,確實是很划算的乙個活動。而對於kdb的認識,也是在對比調優中認識到的,其實結果還是大大超出我的預期。首先來簡單說...