鲁斯前端布鲁斯前端

文章中英模式

布鲁斯前端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
<ul>
  <li>首页</li>
  <li>关于我们</li>
</ul>

// ✅ 好:使用唯一ID
<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,同时保持良好的用户体验,特别是在复杂应用中。