虚拟DOM、diff算法、fiber
在 React 中,Virtual DOM(虚拟 DOM)是一种内存中的表示,它是由 React 创建和维护的一种树形结构,用于表示真实 DOM 的抽象。当状态发生变化时,React 会通过比较新的 Virtual DOM 和旧的 Virtual DOM 的差异来确定需要更新的部分,并将这些变化应用到真实的 DOM 中,从而实现页面的更新。
Virtual DOM 的引入带来了以下好处
- 提高性能:
Virtual DOM 通过将真实 DOM 的操作转换为对虚拟 DOM 的操作,然后批量更新到真实 DOM 中,减少了对真实 DOM 的频繁操作。这样可以提高页面渲染的性能,减少了浏览器重绘和重排的次数,提升了用户体验。
- 减少 DOM 操作的次数:虚拟 DOM 可以将多次操作合并为一次操作,比如添加 1000 个节点,却是一个接一个操作的;
- 减少 DOM 操作的范围:虚拟 DOM 借助 DOM diff 可以把多余的操作省掉,比如添加 1000 个节点,其实只有 10 个是新增的。
简化开发:
使用 Virtual DOM 可以使开发人员更专注于应用程序的逻辑和数据,而不必过多地关注 DOM 操作的细节。通过使用组件化开发模式,开发人员可以将 UI 拆分成小而独立的组件,每个组件都有自己的状态和行为,这样可以更容易地管理和维护应用程序的代码。跨平台兼容性:
由于 Virtual DOM 是一个与平台无关的抽象层,因此可以轻松地将 React 应用程序移植到不同的平台上,包括 Web、移动端和桌面端等。这样可以提高应用程序的可移植性和跨平台兼容性。方便的测试:
使用 Virtual DOM 可以方便地进行单元测试和集成测试,因为可以在内存中操作虚拟 DOM,而无需真实的浏览器环境。这样可以加快测试速度,提高开发效率。
虚拟 DOM 长什么样子?
react:
1 | const vNode={ |
vue:
1 | const vNode={ |
实现虚拟 DOM 例子
- 定义虚拟 DOM 元素
- 创建文本节点
- 将虚拟 DOM 渲染为真实 DOM
1 | // 定义虚拟 DOM 元素 |
虚拟 DOM 的缺点
需要额外的创造函数,如 createElement 或 h,但可以通过 JSX 来简化 XML 写法,严重依赖打包工具
diff 算法
虚拟 DOM 树比较:在进行更新时,React 会将当前的虚拟 DOM 树与新的虚拟 DOM 树进行比较,找出差异。
差异检测:React 使用 深度优先搜索算法(DFS)对比两棵虚拟 DOM 树,找出两棵树之间的差异。它会逐个比较节点及其子节点,找出哪些节点需要更新、添加或删除。
Diff 策略:React 使用了一些优化策略来减少 DOM 操作次数:
- 同层比较:React 只会对比相同层级的节点,不会跨层级比较。
- 唯一标识:在进行节点比较时,React 会使用节点的唯一标识(通常是 key 属性)来判断节点是否相同,从而避免不必要的更新操作。
- 节点移动:React 会尽量复用已存在的节点,而不是重新创建新的节点。如果节点顺序改变,React 会尝试通过移动节点来达到更新效果,而不是直接删除和重新插入节点。
- 批量更新:React 会将多个更新操作合并成一个批量更新,然后一次性更新到真实 DOM 中,以减少页面重绘和重排的次数。
- 应用差异:一旦找到了两棵虚拟 DOM 树之间的差异,React 就会根据这些差异来进行相应的操作,更新真实 DOM。
vue 中的 diff 算法在对新旧虚拟 dom 对比时,是从节点的两侧向中间对比,如果节点的 key 值和元素类型相同,属性值不同,就认为是不同节点,会将该节点删除重建
react 中的 diff 算法在对新旧虚拟 dom 对比时,是从节点的左边向右边对比,如果节点的 key 值和元素类型相同,属性值不同,就认为是节点同类型,只修改当前节点的属性
逻辑
- Tree diff
- 将新旧两棵树逐层对比,找出哪些节点需要更新
- 如果节点是组件就看 Component diff
- 如果节点是标签就看 Element diff
- Component diff
- 如果节点是组件,就先看组件类型
- 类型不同直接替换(删除旧的)
- 类型相同则只更新属性
- 然后深入组件做 Tree diff(递归)
- Element diff
- 如果节点是原生标签,则看标签名
- 标签名不同直接替换,相同则只更新属性
- 然后进入标签后代做 Tree diff(递归)
dom diff 有什么缺点
同级比较,存在 BUG,需要加个 唯一 Key,不能用 index 做下标
Fiber
Fiber 是 React v16 中引入的一种新的协调算法,用于调度和管理 React 的渲染和更新过程。Fiber 的目标是使 React 应用程序更加流畅和响应,减少页面卡顿和掉帧的情况。
Fiber 的核心思想是将 React 的渲染过程分解为可中断的小任务,并且可以根据优先级来调度这些任务的执行顺序。这样可以使 React 在执行渲染任务时更加灵活,可以根据页面的需要来调整任务的优先级和执行顺序,从而提高用户体验。
Fiber 的引入使得 React 具备了更高的并发能力和更灵活的调度策略,使得 React 应用程序可以更好地适应不同的场景和用户需求。
综上所述,Virtual DOM 和 Fiber 是 React 内部机制中的两个关键概念,它们共同作用于 React 的渲染和更新过程中,提高了 React 应用程序的性能、效率和响应能力。Virtual DOM 优化了对真实 DOM 的操作,而 Fiber 则优化了 React 的渲染和更新调度过程。
关于 DOM 的谣言
DOM 操作慢?虚拟 DOM 快
这句话类似于:刘翔矮(对比于姚明)
DOM 操作慢是对比于 JS 原生 API,如数组操作
任何基于 DOM 的库(Vue/React)都不可能再操作 DOM 时比 DOM 快
为什么网上有这样的谣言?
因为在某些情况下,虚拟 DOM 快
规模太大的时候,比如 100000 个节点,原生 DOM 要快,因为虚拟 DOM 要做大量的计算,规模小的时候(1000 个节点),虚拟 DOM 快
在测试插入 10000 个节点的时候,vue 要比 react 快很多,vue 的速度接近原生 JS,当然这两个都没有做任何优化