偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

理解DOM性能優(yōu)化:從重繪回流到虛擬 DOM

開發(fā) 前端
想象一下你在畫畫:重繪(Repaint):?就像只改變畫作的某些顏色,但整體布局不變,回流(Reflow):?相當于把整幅畫重新構(gòu)圖,所有元素的位置大小都要重新計算。

一、什么是重繪與回流?

想象一下你在畫畫:

  • 重繪(Repaint):就像只改變畫作的某些顏色,但整體布局不變。
  • 回流(Reflow):相當于把整幅畫重新構(gòu)圖,所有元素的位置大小都要重新計算。

在瀏覽器中:

  • 回流:當 DOM 的變化影響了元素的幾何屬性(如寬度、高度、位置等), 瀏覽器需要重新計算元素的幾何屬性,并重新構(gòu)建渲染樹。
  • 重繪:當元素的外觀屬性(如顏色、背景色等)發(fā)生改變,但不影響布局時,瀏覽器只需重繪元素。

回流必定會引起重繪,但重繪不一定會引起回流。

導致回流的常見操作:

//幾何屬性變化
element.style.width = '100px';
element.style.height = '100px';
element.style.padding = '10px';


//添加或刪除可見DOM元素
document.body.appendChild(newElement);
element.parentNode.removeChild(element);


//內(nèi)容變化(如文本改變導致尺寸變化)
element.innerHTML = '新內(nèi)容';


//瀏覽器窗口大小改變
window.addEventListener('resize', callback);


//獲取某些屬性(會強制觸發(fā)回流以獲取最新值)
const width = element.offsetWidth;
const height = element.offsetHeight;

只導致重繪的操作:

//顏色相關
element.style.color = 'red';
element.style.backgroundColor = '#fff';


//邊框樣式
element.style.border = '1px solid red';


//可見性
element.style.visibility = 'hidden';

瀏覽器渲染流程是這樣的: 

  1. 解析HTML生成DOM樹.
  2. 解析CSS生成CSSOM樹.
  3. 將DOM和CSSOM合并成渲染樹(Render Tree).
  4. 計算渲染樹的布局(回流).
  5. 將布局繪制到屏幕上(重繪).

每次回流都需要重新計算所有受影響元素的幾何屬性, 然后重繪. 這在復雜頁面中會非常消耗性能. 

舉個例子:

const box = document.getElementById('box');
for (let i = 0; i < 100; i++) {
  box.style.width = box.offsetWidth + 1 + 'px'; //每次循環(huán)都讀取和設置寬度,強制回流
}

這段代碼會導致 100 次回流, 性能非常差。

二、最小化DOM操作

2.1 批量修改DOM

不要一個一個地修改DOM, 而是先把所有修改準備好, 然后一次性應用。

不好的做法: 

const list = document.getElementById('list');
for (let i = 0; i < 10; i++) {
  const item = document.createElement('li');
  item.textContent = `Item ${i}`;
  list.appendChild(item); //每次循環(huán)都操作DOM
}

好的做法: 

const list = document.getElementById('list');
const fragment = document.createDocumentFragment();//使用文檔片段


for (let i = 0; i < 10; i++) {
  const item = document.createElement('li');
  item.textContent = `Item ${i}`;
  fragment.appendChild(item); //先在內(nèi)存中操作
}


list.appendChild(fragment); //最后一次性插入DOM

2.2 使用className而不是style

直接操作 style 屬性會導致多次重繪/回流, 而修改 className 可以批量應用樣式。

不好的做法:

element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.fontSize = '16px';

好的做法:

.highlight {
  color: red;
  background-color: blue;
  font-size: 16px;
}
element.classList.add('highlight');

2.3 脫離文檔流后再進行復雜操作

如果你需要對一個元素進行多次復雜的 DOM 操作, 可以先將它從文檔流中移除, 操作完成后再添加回去。

const list = document.getElementById('list');
const parent = list.parentNode;


//從DOM中移除元素
parent.removeChild(list);


//進行復雜的DOM操作
//...比如添加很多子元素


//操作完成后再添加回DOM
parent.appendChild(list);

2.4 避免頻繁讀取會觸發(fā)回流的屬性

像offsetWidth、offsetHeight、getComputedStyle等屬性會強制瀏覽器觸發(fā)回流來獲取最新值。

不好的做法:

for (let i = 0; i < boxes.length; i++) {
  const width = boxes[i].offsetWidth; //每次循環(huán)都讀取,強制回流
  boxes[i].style.width = width + 10 + 'px';
}

好的做法:

//先讀取所有值
const widths = [];
for (let i = 0; i < boxes.length; i++) {
  widths[i] = boxes[i].offsetWidth;
}


//然后統(tǒng)一設置
for (let i = 0; i < boxes.length; i++) {
  boxes[i].style.width = widths[i] + 10 + 'px';
}

2.5 使用CSS3動畫替代JS動畫

CSS3 動畫可以利用硬件加速, 通常比 JavaScript 實現(xiàn)的動畫性能更好。

不好的做法:

//使用JavaScript實現(xiàn)動畫
function animate(element) {
  let pos = 0;
  const id = setInterval(() => {
    if (pos >= 100) clearInterval(id);
    else {
      pos++;
      element.style.left = pos + 'px';
    }
  }, 10);
}

好的做法:

.box {
  transition: left 1s ease-out;
}

三、虛擬DOM概念介紹

3.1 什么是虛擬DOM?

虛擬DOM(Virtual DOM)是一個用JavaScript對象表示的DOM樹的副本. React、Vue等現(xiàn)代前端框架都使用了虛擬DOM的概念。

//虛擬DOM對象的簡化表示
const virtualNode = {
  tag: 'div',
  props: { id: 'app', class: 'container' },
  children: [
    {
      tag: 'h1',
      props: {},
      children: ['Hello, Virtual DOM!']
    }
  ]
};

3.2 虛擬DOM如何工作?

  1. 初始渲染: 根據(jù)組件創(chuàng)建虛擬DOM樹
  2. 狀態(tài)變化: 當數(shù)據(jù)變化時,創(chuàng)建新的虛擬DOM樹
  3. 差異比較(Diffing): 比較新舊虛擬DOM樹的差異
  4. 批量更新: 只將差異部分應用到真實DOM

3.3 為什么虛擬DOM能提高性能?

  1. 減少直接 DOM 操作: 批量更新, 減少回流和重繪。
  2. 高效的差異算法: 只更新必要的部分。
  3. 跨平臺能力: 虛擬DOM可以渲染到不同平臺(Web、Native等)。

3.4 讓我們實現(xiàn)一個超簡版的虛擬DOM來理解其原理

//創(chuàng)建虛擬DOM節(jié)點的函數(shù)
function h(tag, props, children) {
  return { tag, props, children };
}


//將虛擬DOM渲染為真實DOM
function render(vnode) {
  if (typeof vnode === 'string') {
    return document.createTextNode(vnode);
  }


  const el = document.createElement(vnode.tag);


  //設置屬性
  for (const [key, value] of Object.entries(vnode.props || {})) {
    el.setAttribute(key, value);
  }


  //渲染子節(jié)點
  (vnode.children || []).forEach(child => {
    el.appendChild(render(child));
  });


  return el;
}


//使用示例
const vdom = h('div', { id: 'app' }, [
  h('h1', {}, ['Hello Virtual DOM']),
  h('p', {}, ['This is a simple example'])
]);


const realDOM = render(vdom);
document.body.appendChild(realDOM);

圖片圖片

責任編輯:武曉燕 來源: 全棧程序員老馬
相關推薦

2015-08-11 09:46:26

JavaScriptDOM編程重排

2022-12-08 15:42:36

瀏覽器重繪回流

2024-09-11 16:49:55

2021-01-18 07:15:22

虛擬DOM真實DOMJavaScript

2025-07-03 02:15:00

DOM對象模型JavaScript

2025-07-21 09:30:35

2010-09-28 11:11:23

XML DOMHTML DOM

2011-04-25 10:11:57

高性能web開發(fā)

2021-05-26 05:22:09

Virtual DOMSnabbdom虛擬DOM

2025-02-24 09:10:00

前端VueDOM

2023-02-14 09:37:00

Vue無虛擬模式

2021-01-11 07:51:16

DOM對象節(jié)點樹

2010-09-09 17:19:07

HTML DOMXML DOM

2025-05-08 02:10:00

Vue虛擬DOM

2010-09-28 10:24:50

HTML DOMXML DOM

2023-12-26 10:12:19

虛擬DOM數(shù)據(jù)

2015-07-10 09:24:16

用友

2018-11-14 19:30:57

前端Javascript性能優(yōu)化

2014-05-26 16:16:59

Shadow DomWeb Compone

2010-09-28 09:33:25

DOM模型
點贊
收藏

51CTO技術棧公眾號