diff算法
简述:第一次对比真实dom和虚拟树之间的同层差别,后面为对比新旧虚拟dom树之间的同层差别。
虚拟dom
简述:js对象形容模拟真实dom
具体:
1.虚拟dom是存在内存中的js对象,利用内存的高效率运算。虚拟dom属性远少于dom原生属性,用它来描述真实的dom。虚拟dom并不会在浏览器中显示。
2.虚拟dom如果出现频繁更改,会最后汇总一次性比较并且修改真实dom需要修改的部分,减少了大量重绘,回流
虚拟dom对象具体属性为:
sel:标签名,data:节点属性,children:子节点,elm:对应的真实节点,key:当前节点的key,text:当前节点的文字内容
相较于真实dom的需要比较属性更加的少 效率更加的高。
React-diff 同层左右比较法
分别设置新旧虚拟dom树
react优化diff算法只会同级对比,不会垮级对比,跨级别会直接删除重建,分别为tree-diff component-diff element-diff
tree-diff:逐层比较的过程就为tree-diff,当tree-diff结束的时候时候所有需要更新的元素都会被找到
component-diff:组件级别的对比,组件类型相同则不需要更新,不同则需要删除旧组件创建新组件
element-diff:元素级别的对比,如果两个组件级别相同则是需要元素级别的对比。对于列表渲染react 会强制一个key,对比新旧元素的时候用key进行是否是同一个的判断,如果没有key则是一个个更新,浪费性能。
当使用setState的时候会被标记为脏节点,事件循环的最后才回去渲染脏节点及脏节点的子树。我们可以使用should ComponentUpdate去选择渲染。
从左到右遍历查找更新
vue-diff 前后指针法
分别设置新旧虚拟dom树
设置为新头-startIndex,新尾-endIndex,旧头-oldStartIndex,旧尾-oldEndIndex,分别进行
1.新头-旧头(移动虚拟dom)
2.新尾-旧尾(移动虚拟dom)
3.旧头-新尾(移动真实dom)
4.旧尾-新头(移动真实dom)
的节点比较
如果找到相同的节点则,进行位置更改,1和2是虚拟节点的移动,3和4是进行真实节点的移动
如果新指针指向的节点并没有被匹配到 那么将循环所有的老节点跟新指针指向的节点的key去做农比较,匹配上了移动节点,匹配不成功则新加节点
指针头++ 指针尾-- 直到前指针>后指针结束
如果旧子节点 先处理完了,新子节点有剩余,说明有要新增的节点。
如果新子节点 先处理完了,旧子节点有剩余,说明有要删除的节点。
vue和react diff相同处和区别
相同处:
使用虚拟dom只进行同层的比较
不同处:
react使用的是遍历从左到右,vue使用的为前后指针查找不同。
如果元素的className vue认为是不同的元素,react认为为相同的
如果li中出现了第一个移动li元素移动到最后一个,vue通过前后指针一次性可以直接移动,而react需要遍历到最后才会进行移动。
vue-key
为什么需要设置key?
当4种匹配方法没有正常的匹配到,diff会用key再次进入oldDom中查找。因为key的唯一性可以被Map数据结构充分利用,相比较遍历时间复杂度为On,Map的是时间复杂度为O1。
为什么key最好不要用index?
当4种方法都没有被匹配到的时候,用key进行查找,由于index为数字极大可能会与oldDom里的index重合,diff会判断为相同节点进行处理,但是对比的时候发现并不相同,最终会遍历查找到真实dom上导致重绘回流,性能消耗极大。
特殊例子:当出现input的时候input的输入框如果用index可能会造成input内容并没有更换