魯斯前端布魯斯前端

文章中英模式

布魯斯前端React面試題目 - Virtual DOM 與 React Fiber 解析

深入理解React的Virtual DOM機制與Fiber架構,包括工作原理、效能優化、key的作用以及常見面試題解析。

影片縮圖

懶得看文章?那就來看影片吧

Virtual DOM:原理與優勢

什麼是 Virtual DOM?

Virtual DOM (虛擬 DOM) 是 React 中的一個核心概念,它是真實 DOM 的一種輕量級、純 JavaScript 的表示形式。本質上,它是一個用來描述 DOM 結構及其屬性的 JavaScript 對象樹。

當應用狀態變化時,React 不會直接操作真實 DOM,而是先在記憶體中更新這個虛擬表示,然後通過一個稱為「協調」(Reconciliation) 的過程,高效地計算出需要對實際 DOM 進行的最小更新。

Virtual DOM 表示

// 一個 Virtual DOM 節點的簡化示例
const virtualDOMNode = {
  type: 'div',
  props: {
    className: 'container',
    children: [
      {
        type: 'h1',
        props: {
          children: '標題'
        }
      },
      {
        type: 'p',
        props: {
          children: '段落內容'
        }
      }
    ]
  }
};

// 實際上 React 中的 Virtual DOM 結構更加複雜

對應的 HTML

<!-- 上面 Virtual DOM 對應的實際 HTML -->
<div class="container">
  <h1>標題</h1>
  <p>段落內容</p>
</div>

為什麼需要 Virtual DOM?

操作真實 DOM 是昂貴的,每次直接修改 DOM 會導致瀏覽器進行重排 (reflow) 和重繪 (repaint),特別是在需要頻繁更新 UI 的現代應用中,這會帶來性能瓶頸。

DOM 操作的性能問題

  • 1. 重排和重繪消耗大量計算資源
  • 2. 頻繁的 DOM 操作會導致頁面性能下降
  • 3. 直接修改 DOM 難以追蹤變化
  • 4. 直接操作 DOM 的代碼難以維護和調試

Virtual DOM 的優勢

  • 1. 將多次 DOM 操作合併為一次更新
  • 2. 高效計算出最小必要的 DOM 變更
  • 3. 降低了重排和重繪的次數
  • 4. 提供了聲明式的 UI 編程模型
  • 5. 使跨平台開發變得更加容易

Virtual DOM 的工作流程

React 從 JSX 到頁面渲染的完整流程如下:

JSX → Virtual DOM 樹
Fiber 處理 & Diffing
Reconciliation (可中斷)
Commit (不可中斷)
DOM 更新
useLayoutEffect 執行
瀏覽器繪製畫面
useEffect 執行

通俗解釋:

  • 1. Virtual DOM:就像草稿紙,先在上面畫草圖,而不直接在牆上畫
  • 2. Fiber:把大工作分成小塊,可以隨時暫停處理更重要的事
  • 3. Diffing:比較新舊草圖,只標記需要改動的部分
  • 4. Reconciliation:規劃階段,決定哪些需要更新
  • 5. Commit:執行階段,把變更真正應用到 DOM
  • 6. useLayoutEffect:在畫面顯示前執行,可以測量和調整 DOM
  • 7. useEffect:在畫面顯示後執行,適合處理不急的任務

Virtual DOM Diffing 算法

Diffing 算法是 Virtual DOM 高效性的關鍵。React 實現了一個 O(n) 算法,基於兩個假設:

1. 不同類型元素產生不同樹

如果元素從 div 變成 span,React 會完全重建樹,而不是嘗試匹配。

2. 使用 key 標識穩定元素

添加 key 幫助 React 識別哪些元素是新增、移動或刪除的。

為什麼需要 key?

// 沒有 key 時,React 難以識別變化
<ul>
  <li>首頁</li>
  <li>關於我們</li>
</ul>

// 有 key 時,React 能精確識別
<ul>
  <li key="home">首頁</li>
  <li key="about">關於我們</li>
</ul>

性能提示:Virtual DOM 通常比直接操作 DOM 更高效,但並非在所有場景都是最快的。React 的優勢在於提供良好的開發體驗和合理的性能平衡。

React Fiber:現代協調引擎

什麼是 React Fiber?

React Fiber 是 React 16 引入的協調引擎,重寫了 React 核心算法。它的主要目標是讓 React 能更好地處理大型應用,特別是通過可中斷渲染提高應用響應性。

核心改進:Fiber 之前,React 渲染過程一旦開始就無法中斷,可能阻塞主線程導致頁面卡頓。Fiber 讓渲染過程可以被打斷,優先處理用戶交互。

Fiber 架構的關鍵特性

工作可中斷與恢復

就像在寫一份長報告時,可以先暫停去接電話,然後再回來繼續寫。React Fiber 也是如此,當用戶需要點擊按鈕時,可以暫停正在進行的渲染工作,優先響應用戶操作。

優先級排序

類似醫院的急診分類,危急病人優先處理。React 也會優先處理用戶交互(如按鈕點擊動畫)而非後台數據更新,確保良好的用戶體驗。

Virtual DOM 與 React Fiber 的關係

Virtual DOM 和 React Fiber 雖然是不同概念,但在 React 中緊密協作:

方面Virtual DOMReact Fiber
是什麼DOM的JS對象表示協調引擎
作用描述UI應該是什麼樣子決定如何和何時更新UI
更新方式一次性完成可分段、可中斷

簡單理解:

  • 1. Virtual DOM 告訴 React 「要做什麼」(UI 應該長什麼樣)
  • 2. Fiber 決定 「如何做」(如何高效地更新 DOM)

兩者結合讓 React 既能提供良好的開發體驗(聲明式編程),又能保持出色的性能和響應性。

🔥 常見面試題目

(一)什麼是 Virtual DOM,它如何提升 React 的效能?

解答:

Virtual DOM 是真實 DOM 的 JavaScript 對象表示。就像是一個藍圖,描述了頁面結構但不是真正的頁面。

提升效能的方式:

  • 1. 批量更新:先在記憶體中計算所有變化,再一次性更新真實 DOM
  • 2. 減少操作:只更新真正需要變化的部分,不重繪整個頁面
  • 3. 跨平台:同一套邏輯可以渲染到網頁、手機應用等不同平台

簡單例子:

// Virtual DOM 表示
const vdom = {
  type: 'div',
  props: { className: 'container' },
  children: [
    { type: 'h1', props: { children: '標題' } },
    { type: 'p', props: { children: '內容' } }
  ]
}

需要注意的是,Virtual DOM 不一定總是比直接操作 DOM 更快,但它讓開發者可以用更簡單的方式構建複雜的 UI,同時保持合理的性能。

(二)React Fiber 架構的目的是什麼?它如何改進了 React 的渲染機制?

解答:

Fiber 架構的目的是讓 React 應用更流暢,特別是在處理大量數據和複雜界面時。它就像是把一個大工作分成小塊,可以隨時暫停去處理更重要的事情。

主要改進:

  • 1. 可中斷渲染:長任務可以分段執行,不阻塞主線程
  • 2. 優先級排序:用戶交互可以優先於後台更新
  • 3. 錯誤處理:一個組件出錯不會導致整個應用崩潰

舊版 React

一次性完成所有工作\n↓\n可能造成頁面卡頓

Fiber 架構

工作分成小塊\n↓\n可以暫停處理重要事件\n↓\n頁面保持響應

Fiber 將渲染分為兩個階段:「準備階段」(可中斷)決定要做什麼變更,「提交階段」(不可中斷)將變更應用到 DOM。這讓 React 能夠在保持頁面響應的同時處理複雜更新。

(三)解釋 React 中 key 屬性的重要性,以及如何正確使用它?

解答:

key 屬性就像是列表中每個項目的「身份證」,幫助 React 識別哪些項目變化了、新增了或刪除了。

為什麼重要:

  • 1. 幫助 React 高效更新列表,不需要重建所有項目
  • 2. 保持組件狀態,避免在位置變化時丟失
  • 3. 減少不必要的重渲染,提高性能

正確使用方式:

// ❌ 不好:使用索引作為key
<ul>
  <li>首頁</li>
  <li>關於我們</li>
</ul>

// ✅ 好:使用唯一ID
<ul>
  <li key="home">首頁</li>
  <li key="about">關於我們</li>
</ul>

使用 key 的規則:

  • 1. 在同級元素中必須唯一
  • 2. 應該保持穩定,不要隨機生成
  • 3. 盡量使用數據的ID,避免使用索引

使用索引作為 key 在項目順序變化時會導致問題,因為索引會變但內容可能不變,React 會誤解情況。最好使用來自數據的穩定ID作為 key。

(四)解釋 Virtual DOM 的工作流程,每個階段在做什麼?

解答:

Virtual DOM 的工作流程可以分為幾個關鍵階段,每個階段都有特定的任務:

1. 建立 Virtual DOM 樹

React 將 JSX 轉換為 JavaScript 對象,形成虛擬 DOM 樹。

// JSX
<div className="container">
  <h1>標題</h1>
</div>

// 轉換為 Virtual DOM 對象
{
  type: 'div',
  props: {
    className: 'container',
    children: [{
      type: 'h1',
      props: { children: '標題' }
    }]
  }
}

2. Diffing 比較階段

當狀態更新時,React 創建新的虛擬 DOM 樹,並與舊樹進行比較,找出差異。

舊樹

div (container)
  ├─ h1: "舊標題"
  └─ p: "舊內容"

新樹

div (container)
  ├─ h1: "新標題"
  └─ p: "舊內容"

↓ Diff 結果:只需更新 h1 的文本內容

3. Reconciliation 協調階段

根據 Diff 結果,React 計算出需要對 DOM 進行的最小更改。這個階段是可中斷的,允許瀏覽器處理更高優先級的任務。

// 偽代碼:協調階段的工作單元
{
  type: 'UPDATE',
  element: h1Element,
  newProps: { children: '新標題' },
  priority: 'normal'
}

4. Commit 提交階段

將計算好的變更應用到實際 DOM。這個階段是不可中斷的,一旦開始就會完成所有更新。

// 偽代碼:DOM 更新操作
h1Element.textContent = '新標題';

5. 生命週期與 Hooks 執行

DOM 更新後:執行 useLayoutEffect

瀏覽器繪製後:執行 useEffect

通俗來說,整個流程就像裝修房子:

  • 1. 先在紙上畫設計圖(Virtual DOM)
  • 2. 比較新舊設計圖,標記需要改動的地方(Diffing)
  • 3. 規劃施工順序,可以分階段進行(Reconciliation)
  • 4. 實際動工改造房子(Commit)
  • 5. 檢查施工結果並做最後調整(生命週期與 Hooks)

這種方式讓 React 能夠高效地更新 UI,同時保持良好的用戶體驗,特別是在複雜應用中。