傳統操作DOM消耗性能的原因:DOM的回流(重排)和重繪
-
回流:當頁面的布局或者幾何信息發生變化,瀏覽器可能需要重新創建DOM樹或者重新計算每一個元素在視口中的位置和大小(重新Layout),重新計算完成后,讓瀏覽器重新渲染
- 回流必然會引發重繪
- DOM元素的增刪改導致的DOM結構變化
- DOM的樣式(例如:大小或者位置等)發生改變
- 瀏覽器窗口大小改變(視口改變)
- 頁面第一次加載必然會有一次回流
-
重繪
- 元素樣式發生改變,但是幾何信息和結構信息沒有改變,此時不需要回流,只需要瀏覽器把改變的元素重新渲染即可( color / background-color等)
需求:向#box盒子中動態插入5個span
// 當前代碼會引發5次回流
for (let i = 1; i <= 5; i++) {
let span = document.createElement('span');
span.innerHTML = i;
box.appendChild(span);
優化思路:
- createDocumentFragment 文檔碎片
let frag = document.createDocumentFragment();
for (let i = 1; i <= 5; i++) {
let span = document.createElement('span');
span.innerHTML = i;
frag.appendChild(span);
}
box.appendChild(frag);
frag = null;
- 字符串拼接
let str = ``;
for (let i = 1; i <= 5; i++) {
str += `<span>${i}</span>`;
}
box.innerHTML = str;
現代瀏覽器為了減少樣式更改所引發的回流,都新增了“瀏覽器的渲染隊列”機制
- 上一行代碼是修改元素的樣式,此時并沒有直接通知瀏覽器去渲染,首先把它放置在瀏覽器渲染隊列中,繼續向下執行,把執行中遇到的修改樣式的操作全部放置到瀏覽器的渲染隊列中
- 如果不在有修改樣式的操作,或者遇到了獲取樣式的操作(盒子模型或者獲取樣式),則中斷向隊列中存放的操作,把現有的先渲染一次(引發一次回流),繼續向下執行代碼 = >我們應該“讀寫分離”:把設置樣式和獲取樣式的操作分離開