snabbdom、虚拟Dom、diff算法、

patch函数的整体过程分析

  • patch(oldVnode,newVnode)
  • 把新节点中变化的内容渲染到真实DOM,最后返回新节点作为下一次处理的旧节点
  • 对比新旧VNode是否相同节点(节点的key和sel相同)
  • 如果不是相同节点,删除之前的内容,重新渲染
  • 如果是相同的节点,再判断新的VNode是否有text,如果有并且和oldVnode的text不同,直接更新文本内容
  • 如果新的Vnode有children,判断子节点是否有变化 -------diff算法的核心 updateChildren

Diff算法

虚拟DOM中的Diff算法:
渲染真实DOM的开销很大,DOM操作会引起浏览器的重排和重绘,也就是浏览器的重新渲染,浏览器的重新渲染页面十分耗性能,因为要重新绘制整个页面,当数据变化后,尤其大量数据变化后,比如列表中的数据,如果直接操作DOM的话,会让浏览器重新渲染整个列表。虚拟DOM中diff的核心是当数据变化后不直接操作DOM,而是用js对象描述真实DOM,当数据变化后会先比较js对象是否发生变化,找到发生变化的位置,只去最小化的更新变化的位置,从而提高性能。
虚拟DOM的diff算法用来查找两棵树上每一个节点的差异。diff算法有很多实现方式,传统的diff算法是把第一棵树上的每一个节点一次去跟第二棵树上的每一个节点去对比,如果有n个节点会对比n的平方次。

snabbdom根据DOM的特点对传统的diff算法做了优化

  • DOM操作时候很少会跨级别操作节点
  • 只比较同级别节点 如果同级别节点不同,直接删除,重新创建节点;同级别的节点只需要比较一次,达到减少比较次数的目的,如果有n个节点,只需要比较n次,并且在比较的过程中,同时更新找到的差异

执行过程

在对开始和结束节点比较的时候,总共有四种情况

  • oldStart 和 newStart (旧开始节点 and 新开始节点)
  • oldEnd 和 oldEnd (旧结束节点 and 新结束节点)
  • oldStart 和 newEndt (旧开始节点 and 新结束节点)
  • oldEnd 和 newStar (旧结束节点 and 新开始节点)

开始节点和结束节点

  • 如果新旧开始节点是sameVnode(key 和 sel 相同)

调用 patchVnode() 对比和更新节点
把旧开始和新开始索引往后移动 oldStar++ oldEnd++
在这里插入图片描述
首先根据索引找到旧开始节点和新开始节点,调用sameVnode方法判断新旧节点是不是sameVnode,即比较 key 和 sel 是否相同 ,如果相同,调用 patchVnode 去比较两个节点内部的差异,然后更新到真实DOM。比较完成后,索引移动位置,移动到第二个节点开始比较。把第二个节点作为开始节点比较。
如果开始节点不是 sameVnode ,则开始从后往前比较。
比较旧的结束节点和新的结束节点,如果是 sameVnode , 调用patchVnode方法去比较两个节点内部的差异,然后更新到真实DOM。索引位置往前移动,继续比较。
注意:这里两个节点相同的话,会重用之前旧节点的DOM元素,调用patchVnode比较的时候,会把差异更新到重用的DOM元素上,这个差异可能是文本内容不同或者子元素不同,而当前DOM是不用重新创建的。如果文本内容和子元素都相同,是不会进行DOM操作的,虚拟DOM就是通过这种方式提高性能的

旧开始节点和新结束节点

调用 patchVnode() 对比和更新节点
把 oldStart 对应的DOM元素,移动到右边,更新索引
在这里插入图片描述
比较旧的开始节点和新的结束节点,如果是 sameVnode , 调用patchVnode方法去比较两个节点内部的差异,然后更新到真实DOM。旧的开始节点索引位置移到最右边,更新索引,旧开始节点索引移到2也就是下一个节点,新结束节点往前移动,到5,继续比较。

旧结束节点和新开始节点

调用 patchVnode() 对比和更新节点
把oldEnd对应的DOM元素,移动到左边,更新索引
在这里插入图片描述

比较旧的结束节点和新的开始节点,如果是 sameVnode , 调用patchVnode方法去比较两个节点内部的差异,然后更新到真实DOM。旧的结束节点索引位置移到最前边,更新索引,旧结束节点索引移到5也就是前一个节点,新开始节点往后移动,到2,继续比较。

非上述四种情况

如果以上条件都不满足,说明开始节点和结束节点都不相同
在这里插入图片描述

遍历新的开始节点,在旧节点数组中来查找是否有相同key值得节点,如果没有找到,则说明此时的开始节点是一个新的节点,此时要创建新的DOM元素,插入到最前面的位置;
如果新开始节点在旧节点数组中找到了具有相同key值得节点,并且要判断新旧节点的sel属性是否相同,如果sel不相同,不是相同节点的话,要创建新的DOM元素,把他插入到最前面的位置;如果sel相同,是相同节点,把找到的这个旧节点赋值给 elmToMove 这个变量,然后通过patchVnode这个方法去比较两个节点内部的差异,更新真实DOM,并把elmToMove这个变量节点插入到最前面的位置。

循环结束

  • 老节点的子节点个数 < 新节点的子节点个数 ,老节点先遍历完
    说明新节点有剩余,把剩余节点批量插入到右边
    在这里插入图片描述

  • 新节点的子节点个数 < 老节点的子节点个数 ,新节点先遍历完
    说明老节点有剩余,把剩余节点删除
    在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值