vivatoviva / Interview-Frontend-2020

欢迎star、在对应的ussues沉淀知识
17 stars 2 forks source link

虚拟DOM和Diff算法 #24

Open vivatoviva opened 5 years ago

vivatoviva commented 5 years ago

react将DOM节点抽象为虚拟DOM, 然后通过新旧DOM的差异对比(DIff算法),最终只把变化的部分重新渲染,提高渲染效率的过程,整个过程可以整理如下:

6528244-e275a1d837f6b91b

6528244-df5ff5c7d51e5c8d

为什么要有虚拟DOM?

Diff算法

传统的Diff算法时间复杂度是o(n^3)

react团队结合web页面的特点,做出两个假设,使得diff算法的时间复杂度就直接降低到o(n)

react分别出现三种优化方式,一种是tree diff、component diff以及 element diff算法

Tree Diff

概念: 将新旧两颗虚拟 DOM 树,按照层级对应的关系,从头到尾的遍历一遍,,就能找到那些元素是需要更新的,这种方式: Tree Diff

Tree Diff 01.png

1 只会对相同颜色方框内(同级)的DOM节点进行比较,即同一父节点下的所有子节点
2 当发现节点已经不存在,则该节点及其子节点会被完全删除掉,不会用于进一步的比较
复制代码

Tree Diff 02.png

Component Diff

不同组件之间的对比 概念: 在对比每一个层级的时候,会有自己的组件,这种组件的对比方式就叫: Component Diff ;

​ 这种对比方法其实比较的就是类型.↓↓↓

Component Diff 01.png

Element Diff

同一层级中元素之间的对比 概念: 在类型相同的组件内, 再继续对比组件内部的元素,查看内部元素是否相同,如果需要修改,找到需要修改的元素,进行针对性的修改! 这种方式就叫: Element Diff

三种节点操作:
1 INSERT_MARKUP(插入)
2 MOVE_EXISTING(移动)
3 REMOVE_NODE(删除)

INSERT_MARKUP:新的 component 类型不在老集合里,需要对新节点执行插入操作。

MOVE_EXISTING:老的集合包含新的 component 类型,就需要做移动操作,可以复用以前的 DOM 节点。

REMOVE_NODE:老的 component 不在新集合里的,需要执行删除操作 或者 老的 component 类型在新集合里也有,但对应的 element 不同则不能直接复用和更新,需要执行删除操作
复制代码

Element Diff 01.png

作者:Y__

链接:https://juejin.im/post/5a3200fe51882554bd5111a0

来源:掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

问题

使用key值主要是用于进行diff算法中Element diff,这里面是三种操作,插入、删除、移动,key值可以用来标识一个组件,假设没有key值,当我们在子组件的中插入一个新的节点,那么react的diff算法会认为所有节点的都更新,就会删除现存的节点,然后重新按照新的顺序添加相关节点,这种处理会造成性能的急速下降,所以我们添加key值可以保证让react的diff算法认为这种操作只是头部插入一个节点,不需要重新更新所有节点。具体到相关的算法上如果存在key值的时候可以认为只是一种map映射的关系,如果不存在key值的时候,这种方式是循环进行遍历进行寻找,所以来讲的话,key值是可以让diff变得更加高效。