- 使用 javascript 对象表示 DOM 结构的树形数据结构
- 这个树结构包含整个 DOM 结构的信息
- 真实 DOM 的内存表示,一种编程概念
- 为框架带来了跨平台的能力,抽象了原本的渲染过程,实现了跨平台的能力
- 结合 diff 算法,可以减少 JavaScript 操作真实 DOM 的带来的性能消耗
- 并不是所有情况使用虚拟 DOM 都提高性能,是针对在复杂的的项目使用。如果简单的操作,使用虚拟 DOM,要创建虚拟 DOM 对象等等一系列操作,还不如普通的 DOM 操作
优点:
- 跨平台
- 直接操作/频繁操作 DOM 的性能差
- 操作虚拟 DOM 不会立马进行重绘回流操作,一次性比较并修改真实 DOM 中需要改的部分,再操作 dom
缺点:
- 无法进行极致优化:在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化,比如 VScode 采用直接手动操作 DOM 的方式进行极端的性能优化
- 一种对比算法,对比出是哪个虚拟节点更改了,找出这个虚拟节点,并只更新这个虚拟节点所对应的真实节点,而不用更新其他数据没发生改变的节点,实现精准更新真实 DOM,进而提高效率
- 在某一时间节点调用 React 的 render() 方法,会创建一棵由 React 元素组成的树。在下一次 state 或 props 更新时,相同的 render() 方法会返回一棵不同的树。React 需要基于这两棵树之间的差别来判断如何有效率的更新 UI 以保证当前 UI 与最新的树保持同步
- 新旧虚拟 DOM 对比的时候,Diff 算法比较只会在同层级进行,不会跨层级比较。所以 Diff 算法是深度优先算法,时间复杂度 O(n)
- 把树形结构按照层级分解,只比较同级元素
- 给列表结构的每个单元添加唯一的 key 属性,方便比较
- 同一类型的元素:保留 DOM 节点,仅比对及更新有改变的属性
- 元素类型不同:拆卸原有的树并且建立起新的树
- 如果有子节点,对子节点进行递归
- Keys 是一个辅助标识,用于追踪列表中被修改的元素
- 在 diff 算法中,会借助元素的 key 值来判断该元素是不是新创建的,而减少不必要的重新渲染
- 组件实例是基于它们的 key 来决定是否更新以及复用
- 如果 key 是一个下标,那么修改顺序时会修改当前的 key
- 导致非受控组件的 state(比如输入框)可能相互篡改,会出现无法预期的变动