文章中英模式
布鲁斯前端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 到页面渲染的完整流程如下:
通俗解释:
- 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 DOM | React 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
Fiber 架构
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,同时保持良好的用户体验,特别是在复杂应用中。