无法加载

详解Vue的diff算法

FavoriteLoading收藏

什么是diff算法?

diff算法其实就是虚拟DOM中采用的算法。把树形结构按照层级分解,只比较同级元素。不同层级的节点只有创建和删除操作,给列表结构的每个单元添加唯一的 key 属性,方便比较。

diff算法的源头是snabbdom 算法: https://github.com/snabbdom/snabbdom :一个专注于简单性、模块化、强大功能和性能的虚拟 DOM 库。

为什么要使用diff算法,diff算法的好处是什么?

众所周知,渲染真实DOM的开销非常大,当数据进行修改时,我们如果直接渲染到真实DOM上会引起整个dom树的重绘和重排,那如果我们只是想更新我们修改的那一小块dom呢,这时候diff算法就能帮助到我们。

diff算法可以进行精细化比对,实现最小量更新,diff算法是发生在DOM上的,新虚拟DOM和老虚拟DOM进行diff(精细化比较),算出应该如何最小量更新,最后在反映到真正的DOM上。

虚拟节点结构

{
  children:undefined, //该节点的子节点
  data:{}, //属性、样式等
  elm:undefined //真正的dom节点标签
  key:undefined // 唯一标识,服务于最小更新
  sel:"div" //选择器
  text:"我是一个div" //文本内容
}

如何生成虚拟节点?

是通过h函数来产生虚拟节点

//如果我们这样调用h函数
h('a',{props:{href:'https:qhhhweb.com'}},'Qhhh的个人博客')
//将得到虚拟节点
{"sel":"a","data":{props:{herf:https://qhhhweb.com}},"text":"Qhhh的个人博客"}
//表示的真实节点是这样
<a href="https:qhhhweb.com">Qhhh的个人博客</a>

diff算法的实现流程

无法加载

1、当oldVnode和newVnode进行比较的时候,会调用patch函数,首先会去判断oldVnode是虚拟节点还是DOM节点,如果是DOM节点会去包装(执行vnode函数)为虚拟节点。

2、判断oldVnode和newVnode是不是sel和key都相同,如果不相同就会暴力删除旧的,插入新的。

3、判断oldVnode和newVnode是不是同一个对象,如果不是就会去看newVnode有没有text属性,如果有text属性就会判断是否和oldVnode的text是否一样,如果不一样就把oldVnode的elm的innerText改变为newVnode的text

4、如果newVnode没有text就意味着有children,我们再去判断oldVnode有没有children,如果没有,则意味着oldVnode有text,此时需要清空oldVnode的text,并且把newVnode的children添加到DOM中

5、如果newVnode和oldVnode都有children,此时就需要精细化比较,会进行4种命中查找,这也是最复杂的情况,1、2、3、4按顺序循环命中,一个节点只要命中一个策略就再进行命中判断;如果都没有命中,就需要用循环来命中!

  • 1、新前与旧前
  • 2、新后与旧后
  • 3、新后与旧前(此种情况发生涉及移动节点,将新后指向的节点移动到旧后之后)
  • 4、新前与旧后(此种情况发生涉及移动节点,将新前指向的节点移动到旧前之前)

如果是旧节点先循环完毕,如果新节点中还有剩余节点,说明新节点中有要插入的节点

如果是新节点先循环完毕,如果老节点中还有剩余节点,说明他们是要被删除的节点

如果1、2、3、4都没有命中就需要用循环来寻找(查找到之后移动到oldStartIdx之前)

最后附上小编自己敲的弱化版js版diff算法:https://github.com/qhhh321/study-diff

留下评论

微信:15182814906

QQ:1548902957

邮箱:1548902957@qq.com