diff算法

32 阅读2分钟

一:是什么?

diff算法是一种通过同层的树节点进行比较的高效算法
其中有两个特点:

  • 比较只会在同级进行,不会垮级别比较
  • 在diff比较过程中,循环从两边向中间比较

diff算法在很多场景下都有应用,在vue中,作用于虚拟dom渲染成真实dom的新旧VNode节点比较

二:比较方式

整体策略:深度优先,同层比较
1,比较只会在同层级进行,不会跨层级进行
2,比较过程中,循环从两边向中间收拢

三:原理分析

patch函数前两个参数为oldVnode和Vnode,分别代表新的节点和之前的旧节点,主要做了四个判断:

  • 没有新节点,直接触发旧节点的destory钩子
  • 没有旧节点,说明是页面刚开始初始化的时候,此时,根本不需要比较,直接全是新建,所以只调用createElm
  • 旧节点和新节点自身一样,通过sameVnode判断节点是否一样,一样时,直接调用patchVnode去处理这两个节点
  • 旧节点和新节点自身一样,当两个节点不一样的时候,直接创建新节点,删除旧节点

patchVnode主要做了几个判断:

  • 新节点是否是文本节点,如果是,则直接更新dom的文本内容为新节点的文本内容
  • 新节点和旧节点如果都有子节点,则处理比较更新子节点
  • 只有新节点有子节点,旧节点没有,那么不用比较,所有节点都是全新的,直接全部新建就好,新建是指创建出所有新DOM,并且添加进父节点
  • 只有旧节点有子节点而新节点没有,说明更新后的页面,旧节点全部都不见了,就把所有的旧节点删除,也就是直接把dom删除

小结:

  • 当数据发生变化时,订阅者watcher就会调用patch给真实的DOM打补丁
  • 通过isSameVnode进行判断,相同则调用patchVnode方法
  • patchVnode做了以下操作
    • 找到对应的真实dom,称为el
    • 如果都有文本节点且不相等,将el文本节点设置为Vnode的文本节点
    • 如果oldVnode有子节点而Vnode没有,则删除el子节点
    • 如果oldVnode没有子节点而Vnode有,则将VNode的子节点真实化后添加到el
    • 如果两者都有子节点,则执行updateChildren函数比较子节点

-updateChildren主要做了以下操作

  • 设置新旧VNode的头尾指针
  • 新旧头尾指针进行比较,循环向中间靠拢,根据情况调用patchVnode进行patch重复流程,调用createElem创建一个新节点,从哈希表寻找key一致的VNode节点再分情况操作

参考网站:mp.weixin.qq.com/s?__biz=MzU…