diff算法是如何比较的,保证让你看的明明白白的!

Posted 南风晚来晚相识

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了diff算法是如何比较的,保证让你看的明明白白的!相关的知识,希望对你有一定的参考价值。

更新dom节点,最小力度去跟新

index.html
<body>
    <h1>你好啊!</h1>
    <button id="btn">该变数据</button>
    <div id="container"></div>
</body>
<script src="xuni/bundle.js"></script>
</html>

index.js文件
import 
  init,
  classModule,
  propsModule,
  styleModule,
  eventListenersModule,
  h,
 from "snabbdom";

let myVnode1 = h(\'ul\', , [
  h(\'li\', , \'姓名\'),
  h(\'li\', , \'年龄\'),
  h(\'li\', , \'爱好\'),
])
// 使用init函数创建 patch函数 
const patch = init([classModule, propsModule, styleModule, eventListenersModule])
const container = document.getElementById(\'container\')
// 让虚拟节点上树
patch(container, myVnode1)

// 改变数据
let myVnode2 = h(\'ul\', , [
  h(\'li\', , \'姓名\'),
  h(\'li\', , \'年龄\'),
  h(\'li\', , \'爱好\'),
  h(\'li\', , \'性别\'),

])
let btn = document.getElementById(\'btn\')
btn.onclick = function () 
  patch(myVnode1,myVnode2)

发现的现象

当我手动去更改页面中的数据的时候。
在点击按钮。我们发现只追加了性别。
我更改的数据并没有跟新。
说明diff是进行最小力度去跟新的

那我们把数据添加在最前面会发生什么呢?

let myVnode1 = h(\'ul\', , [
  h(\'li\', , \'姓名\'),
  h(\'li\', , \'年龄\'),
  h(\'li\', , \'爱好\'),
])
// 使用init函数创建 patch函数 
const patch = init([classModule, propsModule, styleModule, eventListenersModule])
const container = document.getElementById(\'container\')
// 让虚拟节点上树
patch(container, myVnode1)

// 改变数据
let myVnode2 = h(\'ul\', , [
  //在最前面添加,发现跟刚才的比一样了?
  //他将我们更改的数据复原了?
  //这个时候又小伙伴会说,diff不是最小粒度去更新了
  h(\'li\', , \'性别\'),
  h(\'li\', , \'姓名\'),
  h(\'li\', , \'年龄\'),
  h(\'li\', , \'爱好\'),
])
let btn = document.getElementById(\'btn\')
btn.onclick = function () 
  patch(myVnode1,myVnode2)

diff不是最小粒度跟新?

在最前面添加,发现跟刚才的比一样了?
他将我们更改的数据复原了?
这个时候又小伙伴会说,diff不是最小粒度去更新了?
其实diff一直都是最小力度跟新,是你忘记增加key值了。
我们加上key值看看呢??

添加key值后

let myVnode1 = h(\'ul\', , [
  h(\'li\', key:\'001\', \'姓名\'),
  h(\'li\', key:\'002\', \'年龄\'),
  h(\'li\', key:\'003\', \'爱好\'),
])
// 使用init函数创建 patch函数 
const patch = init([classModule, propsModule, styleModule, eventListenersModule])
const container = document.getElementById(\'container\')
// 让虚拟节点上树
patch(container, myVnode1)

// 改变数据
let myVnode2 = h(\'ul\', , [
  h(\'li\', key:\'00x\', \'性别\'),
  h(\'li\', key:\'001\', \'姓名\'),
  h(\'li\', key:\'002\', \'年龄\'),
  h(\'li\', key:\'003\', \'爱好\'),
])
let btn = document.getElementById(\'btn\')
btn.onclick = function () 
  patch(myVnode1,myVnode2)

添加key值顶级节点类型改变的情况

当我们添加key值后,发现数据果然是最小力度去更新的,对吧!
如果将ul更改为div,还是最小力度跟新吗?

let myVnode1 = h(\'ul\', , [
  h(\'li\', key:\'001\', \'姓名\'),
  h(\'li\', key:\'002\', \'年龄\'),
  h(\'li\', key:\'003\', \'爱好\'),
])
// 使用init函数创建 patch函数 
const patch = init([classModule, propsModule, styleModule, eventListenersModule])
const container = document.getElementById(\'container\')
// 让虚拟节点上树
patch(container, myVnode1)

// 改变数据
let myVnode2 = h(\'div\', , [
  h(\'li\', key:\'001\', \'姓名\'),
  h(\'li\', key:\'002\', \'年龄\'),
  h(\'li\', key:\'003\', \'爱好\'),
])
let btn = document.getElementById(\'btn\')
btn.onclick = function () 
  patch(myVnode1,myVnode2)


这个时候我们增加上key值了,按照之前的操作。
发现一个问题。数据全部恢复最初始值了。

在采取diff算法比较:新旧节点进行比较,
比较只会在同层级进行, 不会跨层级比较。

如果两个节点都是一样的,那么就深入检查他们的子节点。
果两个节点不一样那就说明 Vnode 完全被改变了(ul和div节点不一样),
就可以直接使用新节点替换老节点。【他们的子代不会进行比较了】 

虽然这两个节点不一样但是他们的子节点一样怎么办?
别忘了,diff可是逐层比较的,
如果[第一层不一样那么就不会继续深入比较第二层了。
(我在想这算是一个缺点吗?相同子节点不能重复利用了??...)

这个时候你可能会说:这个diff算法也不会那么牛逼呢!
并不是最优的。
【虽然这两个节点不一样但是他们的子节点一样怎么办?】
在我们工作中:其实这指一种非常合理的机制。
我们几乎并不会出现这样的情况
<ul v-if="falg">
    <li v-for="item,index" in list>item </li>
</ul>

<ol v-if="falg">
    <li v-for="item,index" in list>item </li>
</ol>
这样的代码在我们工作中几乎是不会出现的呢?

什么叫做不会跨层比较?
<div>
    <p>123123 </p>
</div>
与
<div>
   <h2> <p>123123 </p> </h2>
</div>

div与div比较
p与h2比较
当p与h2比较的时候,他们他们节点不一样,直接使用替换。
此时并不会在使用diff了
作者:明月人倚楼
出处:https://www.cnblogs.com/IwishIcould/

想问问题,打赏了卑微的博主,求求你备注一下的扣扣或者微信;这样我好联系你;(っ•̀ω•́)っ✎⁾⁾!

如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,或者关注博主,在此感谢!

万水千山总是情,打赏5毛买辣条行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主(っ•̀ω•́)っ✎⁾⁾!

想问问题,打赏了卑微的博主,求求你备注一下的扣扣或者微信;这样我好联系你;(っ•̀ω•́)っ✎⁾⁾!

支付宝
微信
本文版权归作者所有,欢迎转载,未经作者同意须保留此段声明,在文章页面明显位置给出原文连接
如果文中有什么错误,欢迎指出。以免更多的人被误导。

以上是关于diff算法是如何比较的,保证让你看的明明白白的!的主要内容,如果未能解决你的问题,请参考以下文章

一张图让你看懂JVM之垃圾回收算法详解

vue3中的四种插槽的介绍-保证让你看看的明明白白!

安全技术3:数据加密之对称加密算法

一文让你看懂什么是vuex

Diff算法

DIff算法看不懂就一起来锤我(带图)