React 思維進化 - Virtual dom

React - Virtual dom
React - Virtual dom
React - Virtual dom
...

新年換新工作後的第一篇文章,就獻給來自『React 思維進化』本書提到的動量級概念——Virtual dom。

對於主流框架來說操作原生 DOM 的代價無疑是巨大的,所以紛紛發展出各自的優秀手段來減少操作所耗費的能量,以下歸納出來自書中提及的、關於為什麼要操作虛擬 DOM 以及操作手法的重點,源自一篇優秀的濃縮精華文章

Virtual dom 真的必要嗎?又沒比較快!

文章開頭的疑問是,在測試操作原生方法來改變渲染的 DOM 結構之後發現 React 或 Angular 都不見效率(時間)上的優勢,那為何要這些框架?這個提問的人顯然非常簡單粗暴說出大部分新手的知識誤區:「快就是好!沒必要優化。」

但發明框架一定有它的道理,從三個方面來說:

好維護

如果不使用框架開發應用程式,將一個肥大的專案打開後滿滿的都是 document.querySelector,你想要從某個功能入手修改的時候你不頭疼?就邏輯歸納來說就好像幫你雜亂的桌子理出個櫃子,每個抽屜好好放入同一個分類的東西,當你想找或者想使用的時候難道沒幫你省下不少時間嗎?
分類的優勢若從 vue 與 react 來說可以切入:

  • vue 的 三大模組切分法(template, style, script)
  • react 的函式導向設計法(functional programming) + hooks

框架幫你掩蓋了底層的操作邏輯,給予多個易於操作的 api 讓你專注開發。

瀏覽器的渲染行為

當你在享受著框架帶來的便利與舒適,一邊訴說與原生 js 的 DOM 操作無差別時,應該思考虛擬 DOM 被發明的意義與出發點,首先對於瀏覽器來說為什麼 DOM 操作代價昂貴——重新渲染。

瀏覽器在 DOM 改變後、渲染畫面經歷的階段:

  1. DOM Tree Update
  2. Reflow/Layout-計算畫面的位置與大小
  3. Repaint
  4. Composite-將畫面元素與 css 繪製合成
  5. Rendering

當這一連串的執行經常發生,就會造成瀏覽畫面的卡頓,其一原理包含了瀏覽器在背後每 16 FPS 渲染畫面的動作,也就是每秒刷新頁面 60 次。
而省去這些成本的大功臣來自於 Virtual dom 背後的辛苦。

Virtual dom 為什麼重要

先講結論:只更新 『必要的』元素。

不同於原生 DOM 操作習慣,例如 innerHTML 每次必定全部渲染,虛擬 DOM 先在藍圖草稿上,操作低成本的 js 對象,規劃與彩排各種情況的 DOM tree,多次演練編排過後的結果才會真正地透過瀏覽器操作原生 DOM。這個過程之所以比預期的慢,是因為進行了幾個背後的努力:

Virtual dom - react

React 採取持續不斷的檢查與比對 DOM 結構(Diff),過程中建立與修改一個個 js dom object 規劃新的 DOM 長相,包含 type, prop, children 等敘述,以便 Diff 完成以後的最終版(patch) 如實透過原生 DOM 產出。

Virtual dom - vue

Vue 則是透過 MVVM 的資料繫結、數據收集後比對差異與變化,各自對應的最小範圍資料經由 ViewModel/Scope 歸納、決定哪些虛擬 DOM 受到影響,這中間產生的複用議題則不如 React 表現好,但仍透過 track by $index 躍升了效能,與之平起平坐。

效率並非時間導向

效率這個假議題從『時間』被拉出來討論背後實際的『渲染』問題才是重點,框架解決的從不是快不快,而是好不好用,能不能直觀開發與維護。