React的虚拟DOM和diff算法

124 阅读3分钟

React中Virtual DOM(虚拟DOM)与diff算法的结合使用,大大的提高渲染的效率,那么他们到底是什么呢?

Virtual DOM(虚拟DOM)

  1. 在React官网中,Virtual DOM 是一种编程概念。在这个概念里, UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中,并通过如 ReactDOM 等类库使之与“真实的” DOM 同步。
  2. 在传统的web中,数据的变化将会实时的影响到DOM的渲染,但是在React中在这两者之间添加了一层叫做Virtual DOM的概念,当数据变化的时候,将不会直接渲染到DOM,而是在Virtual DOM中集中起来,然后一次性的渲染到DOM中,极大的减少了渲染次数

WechatIMG54.png

diff算法

  1. 在react之前,diff算法就已经存在了,只是react对其进行了优化,大大降低了其复杂度,使其由原本的O(n^3) 到了O(n)
  2. react之所以能大大降低其复杂度,主要还是和他们策略改变有很大的关系,主要为tree diff、component diff和element diff三种策略
  • tree diff

    tree diff 主要是对DOM的树形结构进行同层级对比,当发现树形结构的某个分支不存在时,将直接将该节点和其子节点完全删除掉,不会再进一步进行比较,由于React很少进行跨层级的移动操作,所以当出现A节点移动到D节点的子节点的情况发生时,将会直接删除A节点,然后在D节点的子节点中创建新的A节点,不是跨层级的移动操作,而是直接删除与创建。
  • component diff

    component diff 主要是对组件进行比较,当新生成的Virtual DOM和老的Virtual DOM之间的树形结构没有区别时,将进行具体的节点的组件对比,对于不同的组件React做的也是直接删除掉该节点和其所有子节点,重新创建新的节点。

tree diff 和 component diff 看起来似乎有点重复,其实是由很大区别的: tree diff是在最大的树结构中比较 是不是有相同的数量的节点 如果没有则会直接删除 跨层级移动的情况 也直接是删除和创建两种 但是在tree diff比较时 如果是相似的树形结构 只是通过tree diff的比较将无法比较出差异 此时需要的将是component diff的比较方式 具体比较组件之间的差异性 通过组件之间的差异性来达到删除和创建的变动,总的来说tree diff更大,component diff更具体

  • element diff

    当节点处于同一层级时,React diff 提供了三种节点操作,分别为:INSERT_MARKUP(插入)、MOVE_EXISTING(移动)和 REMOVE_NODE(删除)。
    在同一层级间,新老所有的节点之间,将会进行对比,如果组件不同,则会删除,并重新创建,但是有时候我们并不是修改了所有的节点,会造成性能的浪费,这个时候React提供了唯一key的方式对element diff进行优化。
    当使用了key时,进行新老节点对比时,通过keyVirtual DOM将知道新老节点是存在相同节点的,此时通过对比新老节点的index,若是老节点的index < 新节点的index,将会将老节点的组件移动至新节点的index处,反之则保持不变,这样就可以只移动需要移动的值,相比于没有设置key之前的,所有子节点都可能进行的删除和创建,无疑节省了很多的性能

最好不要使用数组的index为key,否则当由删除操作时,key的值将会改变,将会进行重新比较,可能会出现不想见到的变化

参考文档
React深入一文吃透虚拟DOM和diff算法
React 源码剖析系列 - 不可思议的 react diff