specialgirlgotoheaven / MyBlog

MyBlog
0 stars 0 forks source link

虚拟dom-dom diff算法 #154

Open specialgirlgotoheaven opened 5 years ago

specialgirlgotoheaven commented 5 years ago

https://www.cnblogs.com/ranyonsue/p/9831434.html

两棵树如果完全比较时间复杂度是O(n^3),但参照《深入浅出React和Redux》一书中的介绍,React的Diff算法的时间复杂度是O(n)。要实现这么低的时间复杂度,意味着只能平层地比较两棵树的节点,放弃了深度遍历。这样做,似乎牺牲了一定的精确性来换取速度,但考虑到现实中前端页面通常也不会跨层级移动DOM元素,所以这样做是最优的。 我们新创建一棵树,用于和之前的树进行比较.

const newTree = Element('div', { id: 'virtual-container' }, [

Element('h3', {}, ['Virtual DOM']),                     // REPLACE

Element('div', {}, ['after update']),                   // TEXT

Element('ul', { class: 'marginLeft10' }, [              // PROPS

    Element('li', { class: 'item' }, ['Item 1']),

    // Element('li', { class: 'item' }, ['Item 2']),    // REORDER remove

    Element('li', { class: 'item' }, ['Item 3']),

]),

]);

只考虑平层地Diff的话,就简单多了,只需要考虑以下4种情况: 第一种是最简单的,节点类型变了,例如下图中的P变成了h3。我们将这个过程称之为REPLACE。直接将旧节点卸载(componentWillUnmount)并装载新节点(componentWillMount)就行了。 旧节点包括下面的子节点都将被卸载,如果新节点和旧节点仅仅是类型不同,但下面的所有子节点都一样时,这样做显得效率不高。但为了避免O(n^3)的时间复杂度,这样做是值得的。这也提醒了React开发者,应该避免无谓的节点类型的变化,例如运行时将div变成p就没什么太大意义。

第二种也比较简单,节点类型一样,仅仅属性或属性值变了。 第三种是文本变了,文本对也是一个Text Node,也比较简单,直接修改文字内容就行了,我们将这个过程称之为TEXT。 第四种是移动,增加,删除子节点,我们将这个过程称之为REORDER。 具体可以看这篇虚拟DOM Diff算法解析。