1. 定义和作用 (30秒)
"Diff算法是React用来比较新旧虚拟DOM树差异的核心算法。它的主要作用是找出最小的DOM更新操作,避免不必要的重新渲染,从而提升应用性能。"
2. 核心优化策略 (60秒)
"React通过三个关键假设将传统O(n³)的树对比复杂度优化到O(n):
同层比较 :只比较同一层级的节点,不跨层级对比
React 认为,真实 DOM 中
跨层级移动节点的场景极少(比如把一个 div 从子节点移到祖父节点),所以 diff 时只会比对同一层级的节点(比如都在 div 下的子节点)。如果发现某个节点在新树中消失,直接销毁;如果新树中同层多了节点,直接创建;如果节点跨层了(比如父节点变了),也会销毁旧节点、创建新节点。这种 “只看同层” 的策略,大幅减少了比对范围。
组件层级比对:按组件类型判断,类型不同直接卸载。
当比对两个组件节点时,React 会先判断组件类型(比如都是 Button 组件,还是一个是 Button、一个是 Input)。如果类型相同,就认为它们的结构相似,继续递归比对内部子元素;如果类型不同,就直接卸载旧组件、挂载新组件,不再深入比对内部细节。这是因为 React 假设 “不同类型的组件会生成完全不同的 DOM 结构”,这个假设在绝大多数业务场景中成立,进一步减少了无效比对。
元素层级比对(列表场景):用 key 标识唯一性,优化顺序变更。
对于列表类节点(比如多个 li、div 组成的列表),如果没有 key,React 只能按顺序逐个比对,当列表发生插入、删除、重排时,会导致大量元素被错误复用或重复创建(比如在列表头部插入一项,后面所有元素都会被重新渲染)。而 key 的作用是给每个元素一个 “唯一标识”,让 React 能快速定位 “哪些元素是新增的、删除的、移动的”—— 比如旧列表是 [key:1, key:2],新列表是 [key:2, key:1],React 通过 key 能识别出 “只是顺序变了”,只需要移动 DOM 位置,不用重新创建;如果 key 不存在于旧列表,就创建新元素;如果旧列表有 key 但新列表没有,就删除旧元素。
这里要注意:不建议用索引当 key,因为当列表增删时,索引会变化(比如删除第一项,后面元素的索引全变了),导致 key 失效,反而引发更严重的性能问题和状态错乱。
另外,React 16 之后引入的 Fiber 架构,还对 diff 过程做了 “增量更新” 优化 —— 把 diff 任务拆分成小单元,在浏览器空闲时执行,避免长时间占用主线程导致 UI 卡顿,让 diff 过程更 “友好”。