Virtual DOM:為什麼比直接操作 DOM 快?
先釐清:Virtual DOM 不是「比 DOM 快」
❌ "Virtual DOM 比真實 DOM 快"
✅ "Virtual DOM 讓你不需要手動最佳化 DOM 操作"
真實 DOM 操作為什麼慢?
// 每次操作 DOM 都觸發瀏覽器的渲染流程
element.style.width = '100px'; // → 重排(Reflow)
element.style.color = 'red'; // → 重繪(Repaint)
element.style.height = '50px'; // → 又重排
// 三次操作 = 三次渲染計算(瀏覽器可能合併,但不保證)
// 更糟的:
for (let i = 0; i < 1000; i++) {
list.innerHTML += `<li>${i}</li>`; // 每次都重建整個 list!
}
Virtual DOM 的流程
1. State 改變
↓
2. 建立新的 Virtual DOM(純 JS 物件,很快)
↓
3. 和舊的 Virtual DOM 做 Diff(找出差異)
↓
4. 只更新有變化的真實 DOM 節點(最小化 DOM 操作)
// Virtual DOM 就是 JS 物件
const vdom = {
tag: 'div',
props: { className: 'card' },
children: [
{ tag: 'h1', children: ['Hello'] },
{ tag: 'p', children: ['World'] },
]
};
// 比真實 DOM 節點輕量得多
Diff 演算法
舊 VDOM: 新 VDOM:
<ul> <ul>
<li>A</li> <li>A</li>
<li>B</li> <li>B</li> ← 沒變
<li>C</li> <li>D</li> ← 改了(只更新這個)
</ul> <li>E</li> ← 新增
</ul>
→ 真實 DOM 操作:
1. 把第三個 <li> 的文字從 C 改成 D
2. 新增一個 <li>E</li>
→ 只碰了 2 個節點,不是重建整個列表
Key 的重要性
// ❌ 沒有 key → React 不知道哪個項目對應哪個,整個重建
{items.map(item => <li>{item.name}</li>)}
// ✅ 有 key → React 精確知道哪個項目變了
{items.map(item => <li key={item.id}>{item.name}</li>)}
什麼時候 Virtual DOM 反而慢?
1. 極少的 DOM 操作(直接改一個元素比建 VDOM + diff 快)
2. 大量節點的初始渲染(建立 VDOM 本身有成本)
3. 超高頻更新(Canvas 動畫不適合用 React)
Virtual DOM 的價值不是「最快」,而是讓你用「宣告式」寫 UI,框架自動幫你做最佳化。手動操作 DOM 做得好可以更快,但很難維護。
替代方案
Svelte:編譯時期就知道哪裡會變,不需要 VDOM
→ 編譯成直接操作 DOM 的程式碼
→ 執行時更快(沒有 diff 開銷)
→ 但生態系不如 React/Vue
SolidJS:響應式信號,細粒度更新
→ 只更新有變化的 DOM 節點
→ 不需要 VDOM diff