2023-08-18 17:05:26
Diff算法是用于生成虚拟DOM树更新补丁,以最小成本完成真实DOM视图更新的算法。其核心在于对比新旧虚拟DOM树的差异,并将这些差异结构化为补丁数据,最终作用于真实DOM。以下是具体说明:

更新时机更新由setState、Hooks调用等触发,这些操作会标记虚拟DOM树为“脏状态”,启动Diff流程。
遍历算法采用深度优先遍历,从根节点纵向遍历左子树至叶子节点,回溯后遍历右子树。此方式确保所有可达节点被访问,但传统实现效率较低。
优化策略通过分治策略将节点比对细分为三类,显著提升效率:
树比对:仅比较同一层级节点,跨层级操作视为完全删除旧节点并新建。例如,若旧树某层节点在新树中不存在,则该节点及其子树被丢弃。
组件比对:组件类型相同则复用树结构,否则直接替换。父组件类型变化会导致子组件重新渲染,这也是shouldComponentUpdate、PureComponent和React.memo能优化性能的原因。
元素比对:同层级节点通过key标记进行列表对比,key帮助React识别节点移动、插入或删除,避免不必要的DOM操作。例如,列表排序时key可减少节点重建。

React 16引入Fiber机制后,Diff过程实现可中断和恢复:
数据结构重构:
FiberNode采用双链表结构,每个节点存储兄弟节点和子节点指针,支持快速遍历。
FiberTree由FiberNode构成,代表整个组件树。
双缓冲树:
current树:当前显示的UI对应的Fiber树。
workInProgress树:正在构建的新UI对应的Fiber树。更新完成后,通过指针切换直接替换current树,避免频繁的DOM操作。
时间切片:Fiber将渲染任务拆分为小单元,浏览器空闲时执行,避免长时间阻塞主线程,提升交互流畅度。
React:
完整Diff策略+时间切片能力,适合大批量节点更新场景。
Fiber架构实现可中断渲染,优化用户体验。
Preact:
设计思路与React相似,但直接操作真实DOM,未实现Fiber。
适用于轻量级场景,性能要求不高时可作为React替代。
Vue:
Diff策略与React对齐,但未采用时间切片(Vue 3曾尝试后移除)。
通过防抖和节流优化响应性能,高帧率动画外场景表现良好。
总结:Diff算法通过虚拟DOM比对和结构化补丁生成,最小化真实DOM操作。React的优化策略(树/组件/元素比对)和Fiber架构使其在复杂场景中表现优异,而Vue和Preact则通过简化设计满足不同需求。