网站建设教程高清视频,郑州网络运营培训,国网典型设计最新版,制作wordpress页面模板核心要点
数据变化时#xff0c;vue如何更新节点虚拟DOM 和 真实DOM 的区别vue2 diff 算法vue3 diff 算法
一、 数据变化时#xff0c;vue如何更新节点
首先渲染真实DOM的开销是很大#xff0c;比如有时候我们修改了某个数据且修改的数据量很大时#xff0c;此时会频繁的…核心要点
数据变化时vue如何更新节点虚拟DOM 和 真实DOM 的区别vue2 diff 算法vue3 diff 算法
一、 数据变化时vue如何更新节点
首先渲染真实DOM的开销是很大比如有时候我们修改了某个数据且修改的数据量很大时此时会频繁的操作真实dom会不断的引起整个dom树的重绘和重排vue是根据真实DOM生成一颗 虚拟DOM当 虚拟DOM 某个节点的数据改变后会生成一个新的newVnode然后newVnode和oldVnode作对比发现有不一样的地方就直接修改在真实的DOM上
二、虚拟DOM 和 真实DOM 的区别
虚拟DOM是将真实的DOM的数据抽取出来以对象的形式模拟树形结构
//真实DOM
divp123/p
/div//虚拟DOM
var Vnode {tag: div,children: [{ tag: p, text: 123 }]
};三、vue2 diff 算法
核心原理
深度优先同层比较时间复杂度只有 O(n)双针比较新头与旧头比较新尾与旧尾比较旧头与新尾比较新头与旧尾比较
diff算法流程
1diff算法是发生在更新的过程而更新的情况有以下几种情况
老的是Text新的是Text直接更新老的是Array新的是Text把旧的全部删掉更新为Text老的是Text新的是Array删掉旧的文本更新为新的Array元素老的是Array新的是Array调用updateChildren函数比较子节点这是diff的核心
2老的是Array新的是Array的情况下调用updateChildren函数diff核心流程
新旧节点VNode节点如下图所示 循环遍历节点 ① 情况当新老 VNode 节点的 start 满足 sameVnode 时直接 patchVnode 即可同时新老 VNode 节点的开始索引都加 1if (sameVnode(oldStartVnode, newStartVnode)) {patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)oldStartVnode oldCh[oldStartIdx]newStartVnode newCh[newStartIdx]
}② 情况当新老 VNode 节点的 end 满足 sameVnode 时同样直接 patchVnode 即可同时新老 VNode 节点的结束索引都减 1else if (sameVnode(oldEndVnode, newEndVnode)) {patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)oldEndVnode oldCh[--oldEndIdx]newEndVnode newCh[--newEndIdx]
}③ 情况当老 VNode 节点的 start 和新 VNode 节点的 end 满足 sameVnode 时这说明这次数据更新后 oldStartVnode 已经跑到了 oldEndVnode 后面去了。这时候在 patchVnode 后还需要将当前真实 dom 节点移动到 oldEndVnode 的后面同时老 VNode 节点开始索引加 1新 VNode 节点的结束索引减 1else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved rightpatchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)canMove nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))oldStartVnode oldCh[oldStartIdx]newEndVnode newCh[--newEndIdx]
}④ 情况当老 VNode 节点的 end 和新 VNode 节点的 start 满足 sameVnode 时这说明这次数据更新后 oldEndVnode 跑到了 oldStartVnode 的前面去了。这时候在 patchVnode 后还需要将当前真实 dom 节点移动到 oldStartVnode 的前面同时老 VNode 节点结束索引减 1新 VNode 节点的开始索引加 1。else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved leftpatchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);canMove nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);oldEndVnode oldCh[--oldEndIdx];newStartVnode newCh[newStartIdx];
}⑤ 以上都不满足的情况如果新旧子节点都存在key那么会根据oldVnode的key生成一张hash表用当前新节点暂时称为S的key与hash表做匹配匹配成功就判断S和匹配节点是否为sameNode如果是就在真实dom中将成功的节点移到最前面否则将S生成对应的节点插入到dom中对应的oldS位置S指针向中间移动被匹配old中的节点置为undefined。如果没有key,则直接将S生成新的节点插入真实DOMps这下可以解释为什么v-for的时候需要设置key了如果没有key那么就只会做四种匹配就算指针中间有可复用的节点都不能被复用了
四、vue3 diff 算法
核心原理
深度优先同层比较时间复杂度只有 O(n)双端对比算法先看左侧看完左侧看右侧然后锁定中间乱序的部分最长递增子序列针对中间乱序部分采用最长递增子序列的算法计算出乱序部分可以复用的最长连续节点
diff算法流程
1diff算法是发生在更新的过程而更新的情况有以下几种情况
老的是Text新的是Text直接更新老的是Array新的是Text把旧的全部删掉更新为Text老的是Text新的是Array删掉旧的文本更新为新的Array元素老的是Array新的是Array调用updateChildren函数比较子节点这是diff的核心
2老的是Array新的是Array的情况下调用updateChildren函数diff核心流程 先处理左侧先从左侧开始进行对比很明显左侧的A、B都是相同的然后锁定左侧相同的部分处理右侧乱序部分 再处理右侧从右侧开始对比很明显右侧的B、C都是相同的然后锁定右侧相同部分处理左侧乱序部分 若新的比老的长创建可以看到下图新的比老的多新的多了一个D多出来的这个节点就需要创建并添加到尾部 老的比新的长删除可以看到下图老的比新的多了个C多出来的这个节点需要删除 乱序部分采用最长递增子序列的算法最大递增子序列的作用就是通过新旧节点变化前后的映射创建一个递增数组这样就可以知道哪些节点在变化前后相对位置没有发生变化哪些节点需要进行移动如下图计算出E、F、Y、J 是不需要操作的节点直接复用然后移动K节点即可完成一次更新关于最长递增子序列的算法参考视频算法核心动态规划二分法实现驱节点向前回溯 的方式实现了On logn的时间复杂度查找
参考文章
Vue2、Vue3的diff对比根据大崔哥的mini-vue来理解vue3中的diff算法手写Vue3框架教程核心原理、组件渲染、diff算法、生命周期…)