前端框架
-虛擬 DOM 是什麼?(Virtual DOM)
this.web

虛擬 DOM 是什麼?
自從 React 開始流行後,虛擬 DOM 也漸漸廣為人知,很多面試很愛考虛擬 DOM 的相關知識。了解虛擬 DOM 也是掌握 React 或 Vue 底層原理的第一步。
什麼是虛擬 DOM
虛擬 DOM (Virtual DOM) 是一種概念,並不是真實存在的東西或是瀏覽器中的 DOM。
他是利用 JavaScript 物件來一對一描述 DOM,是一種虛擬的 UI 表現方式。
透過這種虛擬的表達方式,前框框架就能用聲明式的方式來描述 UI 狀態,接著框架內部會負責確保瀏覽器中的畫面和我們描述的 UI 相同。比如 React 的 JSX 就是一種描述 UI 的方式。而 React 內部後透過 Reconciler 去實現畫面,並不用我們手動去操作。
為什麼要虛擬 DOM?
在 React 之前,前端開發主要採用傳統的 MVC、MVVM 架構或直接使用 jQuery 操控 DOM 等方式,但隨著專案的複雜度提升,這種手動更新 DOM 的方式,會在頻繁更新 UI 時暴露出效率問題。
例如利用 innerHTML 的方式直接修改 DOM,就是一個效率不太好的方式,因為他會需要重新解析 DOM 樹並經歷 reflow 和 repaint。
除了效能以外,操作 DOM 的程式也會散落在各處,照成專案難以維護。
因此為了解決這些問題,React 利用虛擬 DOM,也就是一個 JS 物件,當 UI 更新時,也就是我們調用 setState 時,他會先比較新舊的虛擬 DOM,找出更新的最小差別(可能是文字、元素屬性…),針對這個地方單獨更新,以此來降低更新畫面的成本。
虛擬 DOM 的優點
從上面的敘述,我們可以看出虛擬 DOM 的優點:
- 降低直接操作 DOM 的成本:直接對真實 DOM 的修改可能導致瀏覽器大量的排版和重繪,虛擬 DOM 則將多次修改集中起來,通過一次 diff 計算後批量更新,避免了不必要的重排和重繪。
- 開發便利性與可維護性:有了虛擬 DOM,我們工程師就不用再手動尋找和更新特定的 DOM 節點,只需關注狀態數據,框架會根據虛擬 DOM 和資料綁定自動更新UI。大幅提升了開發效率,也減少了人工操作 DOM 容易引入的錯誤。
- 跨平台支持:虛擬 DOM 是純 JS 結構,與瀏覽器平台無關。因此可以輕鬆地擴展到其他平台,例如 React 就透過虛擬 DOM 機制,搭配不同的 renderer,將更新應用到原生行動介面(React Native)或進行伺服器端渲染。讓同一套 UI 邏輯可重用於不同環境。
虛擬 DOM 的缺點
在軟體世界中沒有所謂的萬靈丹,相對的,虛擬 DOM 也有一些缺點:
- 需引入額外的計算與記憶體開銷:使用虛擬 DOM 代表每次更新都需要建立新的虛擬 DOM 樹,並執行 Diff 演算法比較新舊虛擬 DOM 的差異。
- 額外的實作複雜度:對框架本身而言,引入虛擬 DOM 要額外的實作和維護複雜的 diff 演算法和更新機制。在少數情況下可能會出現預料之外的更新問題,例如列表的 key 沒有正確提供導致 diff 判斷失誤,或是條件渲染時出現狀態沒有初始化的問題等等。
也是因為這些問題,一些較新的框架像是 Svelte,以及 Vue 的 vaper mode 就直接不依賴虛擬 DOM,而是採用先編譯的策略,也就是在 build time 就先將操控 DOM 的最小邏輯寫好。
不過在大多數場景下,虛擬 DOM 帶來的效能提升還是大於其開銷問題的。
虛擬 DOM 真的比直接操作 DOM 高效嗎?
不一定,如同上面所說,虛擬 DOM 是需要經過一系列新舊虛擬 DOM 的比較的,這個運算不見得比直接操作 DOM 來得快。
但是虛擬 DOM 透過「避免不必要的更新」與「批次提交」兩個機制,以及將操作 DOM 的機制隱藏在框架內部,讓我們能在大多數場景下,能享受更好的效能與開發體驗。
總結
虛擬 DOM 是一種以 JavaScript 物件樹描述 UI、並在執行期以 diff 演算法決定最小化真實 DOM 更新的技術。
它有集中更新、跨平台 Render 的優點,但同時也有引入額外記憶體與運算成本的缺點。
也因此 Svelte 和 Vue vapor 不依賴虛擬 DOM,而是先編譯期產生精確 DOM 操作來提升效能。