传统diff和react虚拟diff

266 阅读2分钟

React diff原理探究以及应用实践

segmentfault.com/a/119000001…

react的diff 从O(n^3)到 O(n) ,请问 O(n^3) 和O(n) 是怎么算出来?

www.zhihu.com/question/66…

diff策略:

Web UI中DOM节点跨层级的移动操作特别少,可以忽略不计。

拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件将会生成不同的树形结构。

对于同一层级的一组子节点,它们可以通过唯一 id 进行区分

在上面三个策略的基础上,React 分别将对应的tree diff、component diff 以及 element diff 进行算法优化,极大地提升了diff效率。

1.tree diff(两棵组件树之间的比较。比较两棵树的结构)

2.component diff(组件的差异比较过程)

React 是基于组件构建应用的,对于组件间的比较所采取的策略也是非常简洁、高效的。 如果是同一类型的组件,按照原策略继续比较 Virtual DOM 树即可。 如果不是,则将该组件判断为 dirty component,从而替换整个组件下的所有子节点。 对于同一类型的组件,有可能其 Virtual DOM 没有任何变化,如果能够确切知道这点,那么就可以节省大量的 diff 运算时间。

因此,React允许用户通过shouldComponentUpdate()来判断该组件是否需要进行diff算法分析,但是如果调用了forceUpdate方法,shouldComponentUpdate则失效。

3.element diff(同一层级同一父元素下的节点集合,进行比较,真实DOM渲染前,比较节点结构的变化)

当节点处于同一层级时,diff 提供了 3 种节点操作,分别为 INSERT_MARKUP (插入)、MOVE_EXISTING (移动)和 REMOVE_NODE (删除)。

INSERT_MARKUP :新的组件类型不在旧集合里,即全新的节点,需要对新节点执行插入操作。

MOVE_EXISTING :旧集合中有新组件类型,且 element 是可更新的类型,generateComponentChildren 已调用receiveComponent ,这种情况下 prevChild=nextChild ,就需要做移动操作,可以复用以前的 DOM 节点。

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