当前位置: 首页 > news >正文

中国建设银行北京招聘信息网站网络服务器搭建

中国建设银行北京招聘信息网站,网络服务器搭建,免费找人网站 优帮云,桂林市网站设计VUE DIFF算法系列讲解 VUE 简单DIFF算法 VUE 双端DIFF算法 文章目录VUE DIFF算法系列讲解前言一、快速DIFF的代码实现二、实践练习1练习2总结前言 本节我们来写一下VUE3中新的DIFF算法-快速DIFF,顾名思义,也就是目前最快的DIFF算法(在VUE中&…

VUE DIFF算法系列讲解

VUE 简单DIFF算法
VUE 双端DIFF算法


文章目录

  • VUE DIFF算法系列讲解
  • 前言
  • 一、快速DIFF的代码实现
  • 二、实践
    • 练习1
    • 练习2
  • 总结


前言

本节我们来写一下VUE3中新的DIFF算法-快速DIFF,顾名思义,也就是目前最快的DIFF算法(在VUE中)
本节内容值包括快速DIFF算法的实现,不考虑最长递增子序列算法的实现


一、快速DIFF的代码实现

相对于我们此系列的前两种DIFF算法,此DIFF算法在进入真正的DIFF算法之前,会有一个预处理的过程,这个主要是借鉴了纯文本Diff算法的思想。下边,我们就直接通过代码看下整个Diff的实现流程。

const oldChildren = n1.children;
const newChildren = n2.children;// 预处理开始
// 处理新旧子节点的头部可复用节点
let j = 0;
let oldVNode = oldChildren[j];
let newVNode = newChildren[j];
while (oldVNode.key === newVNode.key) {// 打补丁patch(oldVNode, newVNode, container);// 更新VNodej++;oldVNode = oldChildren[j];newVNode = newChildren[j];
}// 处理新旧节点尾部可复用节点, 因为新旧子节点长度可能不一致,所以需要定义两个变量
let oldEnd = oldChildren.length - 1;
let newEnd = newChildren.length - 1;oldVNode = oldChildren[oldEnd];
newVNode = newChildren[newEnd];while (oldVNode.key === newVNode.key) {// 打补丁patch(oldVNode, newVNode, container);// 更新VNodeoldEnd--;newEnd--;oldVNode = oldChildren[oldEnd];newVNode = newChildren[newEnd];
}
// 预处理结束后// 预处理结束会有三种情况:1.新子节点有剩余;2.旧街店有剩余;3:新旧节点均有剩余
if (j > oldEnd && j <= newEnd) {// 如果新子节点有剩余// 获取锚点idlet anchorIdx = newEnd + 1;// 获取锚点node,如果let anchor = anchorIdx === newChildren.length ? newChildren[anchorIdx].el : null;while (j <= newEnd) {// 挂载patch(null, newChildren[j++], container, anchor);}
} else if (j > newEnd && j <= oldEnd) {// 如果旧节点有剩余,则需要卸载while (j <= oldEnd) {unmount(oldChildren[j++]);}
} else {// 如果新旧节点均有剩余// 构造source数组const count = newEnd - j + 1;let source = new Array(count);source.fill(-1);// 新旧子节点的起始indexconst oldStart = j;const newStart = j;let pos = 0;let moved = false;// 构建新子节点的{key: index} 对象const keyIndex = {};for (let i = newStart; i < newEnd; i++) {keyIndex[newChildren[i].key] = i;}// 保存已被处理过的旧子节点数let patched = 0;// 填充sourcefor (let i = oldStart; i <= oldEnd; i++) {oldVNode = oldChildren[i];if (patched <= count) {const k = keyIndex[oldVNode.key];if (k !== undefined) {// 打补丁newVNode = newChildren[i];patch(oldVNode, newVNode, container);patched++;source[k - newStart] = i;if (k < pos) {moved = true;} else {pos = k;}} else {// 没有找到,卸载unmount(oldChildren[i]);}} else {// 处理数已等于新子节点数,其余卸载unmount(oldChildren[i]);}}// 如果需要移动if (moved) {const seq = lis(source);let s = seq.length - 1;let i = count - 1;for (i; i >= 0; i--)if (source[i] === -1) {// 这种情况属于新增const pos = i + newStart;const newVNode = newChildren[pos];// 获取锚点的索引const newPos = pos + 1;// 锚点const anchor = newPos < newChildren.length ? newChildren[newPos] : null;// 挂载patch(null, newVNode, container, anchor);} else if (seq[s] !== i) {// 这种情况需要移动const pos = i + newStart;const newVNode = newChildren[pos];// 获取锚点的索引const newPos = pos + 1;// 锚点const anchor = newPos < newChildren.length ? newChildren[newPos] : null;// 挂载insert(newVNode, container, anchor);} else {// 当 i === seq[j] 时,说明该位置的节点不需要移动// 并让 s 指向下一个位置s--;}}
}

二、实践

练习1

// 旧子节点
p-1 p-2 p-3
// 新子节点
p-1 p-3// 预处理开始
// while循环对比,预处理头部可服用量节点
let j = 0
newVNode = p-1
oldVNode = p-1
// 第一次循环 j=0
newVNode.key === oldVNode.key 可复用 j++
newVNode = p-2
oldVNode = p-3
// 第二次循环
newVNode.key !== oldVNode.key 跳出循环//  while循环对比,预处理尾部可服用量节点
let oldEnd = 2(oldChildren.length - 1);
let newEnd = 1(newChildren.length - 1);
oldVNode = p-3(oldChildren[oldEnd]);
newVNode = p-3(newChildren[newEnd]);
// 第一次循环 oldEnd=2 newEnd=1
newVNode.key === oldVNode.key 可复用 oldEnd-- newEnd--
newVNode = p-2
oldVNode = p-1
// 第二次循环 oldEnd=1 newEnd=0
newVNode.key !== oldVNode.key 跳出循环
// 预处理结束// 预处理结束,此时j(1)>newEnd(0) && j(1)<=oldEnd(1),说明旧的子节点有剩余,仅需要将剩余子节点卸载即可

练习2

// 旧子节点
p-1 p-2 p-3 p-4 p-6 p-5
// 新子节点
p-1 p-3 p-4 p-2 p-7 p-5// 预处理开始
// while循环对比,预处理头部可服用量节点
let j = 0
newVNode = p-1
oldVNode = p-1
// 第一次循环 j=0
newVNode.key === oldVNode.key 可复用 j++
newVNode = p-2
oldVNode = p-3
// 第二次循环
newVNode.key !== oldVNode.key 跳出循环//  while循环对比,预处理尾部可服用量节点
let oldEnd = 5(oldChildren.length - 1);
let newEnd = 5(newChildren.length - 1);
oldVNode = p-5(oldChildren[oldEnd]);
newVNode = p-5(newChildren[newEnd]);
// 第一次循环 oldEnd=2 newEnd=1
newVNode.key(p-5) === oldVNode.key(p-5) 可复用 oldEnd-- newEnd--
newVNode = p-7
oldVNode = p-6
// 第二次循环 oldEnd=4 newEnd=4
newVNode.key !== oldVNode.key 跳出循环
// 预处理结束// 此时真实dom节点如下
p-1() p-2 p-3 p-4 p-6 p-5()
// 待处理
p-2 p-3 p-4 p-6---------------------------------------------
// 预处理结束,此时j(1)<=newEnd(4) && j(1)<=oldEnd(4),说明新旧的子节点有剩余,此时我们需要构建一个sourece数组,这个数组长度为新子节点在预处理后剩余未处理的节点数,并且初始值为-1// 新子节点未处理完的节点数
const count = newEnd - j + 1;
// 构建source数组
let source = new Array(count);
source.fill(-1);
// 定义新旧子节点的起始index
const oldStart = j(1);
const newStart = j(1);
// 定义在旧子节点便利过程中遇到的最大的索引值
let pos = 0;
// 代表是否需要移动节点
let moved = false;
// 定义一个数量表示,表示已经处理过的子节点数.如果已处理过的子节点数超过新子节点数,则表示其余的为多余节点,直接卸载
let patched = 0// 构建一个索引表,此表内存储新子节点中,key与index的映射
keyIndex = {p-3 : 1,p-4 : 2,p-2 : 3,p-7 : 4
}// 填充source数组并处理多余oldVNode
// 开始循环 
// 第一次循环 i(oldStart) = 1; oldEnd = 4; count = 4; pos = 0;
oldVNode    patched      kp-2          0         3
k !== undefined patched++ pos=k i++
source = [-1, -1, 1, -1]
// 第二次循环 i = 2; oldEnd = 4; count = 4; pos = 3
oldVNode    patched      kp-3          1         1
k !== undefined patched++ moved = true
source = [2, -1, 1, -1]
// 第三次循环 i = 3; oldEnd = 4; count = 4; 因moved为true,所以不再需要关心pos
oldVNode    patched      kp-4          2         2
k !== undefined patched++ 
source = [2, 3, 1, -1]
// 第四次循环 i = 4; oldEnd = 4; count = 4; 
oldVNode    patched      kp-6          3      undefined
k === undefined 卸载
source = [2, 3, 1, -1]
// 第四次循环 i = 5; oldEnd = 4; i > oldEnd 跳出循环// 此时真实dom节点如下
p-1() p-2 p-3 p-4 p-6() p-5()
// 待处理
p-2 p-3 p-4
---------------------------------------------------------// 因moved为true,所以需要进行移动
// 构建一个最长递增子序列(此节中暂不考虑最长递增子序列算法)
const seq = [0, 1]
// 定义s, 其值为最长递增子序列的最大index
let s = 1
// 定义i, 其值为source的最大index
let i = 3// 开始循环
// 第一次循环 i = 3;
source[3] = -1, 则此节点为新增节点,需要挂载,锚点为p-5
// 此时真实dom节点如下
p-1() p-2 p-3 p-4 p-7() p-5()// 第二次循环 i = 2;
source[2] = 1, 
seq[1] !== 2 此节点需要移动, 锚点为p-7
// 此时真实dom节点如下
p-1() p-3 p-4 p-2() p-7() p-5()// 第三次循环 i = 1;
source[1] = 3, 
seq[1] === 1 此节点不需要移动 s--
// 此时真实dom节点如下
p-1() p-3 p-4() p-2() p-7() p-5()// 第四次循环 i = 0;
source[0] = 2, 
seq[0] === 0 此节点不需要移动
// 此时真实dom节点如下
p-1() p-3() p-4() p-2() p-7() p-5()

总结

快速Diff算法的整体逻辑还是比较容易理解的,其中比较巧妙的是预处理和source的用法。学习快速Diff算法不仅让我们更深刻的了解了VUE3,同时其中的一些核心逻辑,也可以为我们的日常开发工作中提供一些开发思路。

参考:<<vue设计与实现>>第10章
github:link

http://www.mmbaike.com/news/30284.html

相关文章:

  • 三水建设局网站搜索引擎营销的原理是什么
  • 沈阳专业seo快速排名优化推广排名
  • 大足专业建站公司如何推广外贸型网站
  • 南山的网站设计常见的搜索引擎有哪些
  • 智能建站系统开发关键词搜索查询
  • 做电商网站赚钱吗seo优化的优点
  • 重庆建设工程信息网证书查询官网太原关键词排名优化
  • 3 建设营销型网站流程图百度推广seo优化
  • 百度商桥怎么和网站写软文的平台有哪些
  • 网站上的图标用什么软件做的四川百度推广排名查询
  • 网站优化分析软件可以看封禁网站的浏览器
  • wordpress页面美化太原网站制作优化seo公司
  • 做网站和做app哪个简单百度推广账号登陆入口
  • 赚钱链接网站百度一下你知道
  • 邯郸企业做网站报价山西seo优化
  • 工商注册实名认证惠州百度seo地址
  • 可以打开的wap网站网址收录
  • 西藏自治区住房和城乡建设部网站个人博客网站
  • 莱州网站建设谷歌浏览器搜索引擎入口
  • 深圳瑞捷成立新公司广东seo
  • 网站后台模板修改用什么软件怎么自己弄一个平台
  • 网站建设首页突出什么百度一下首页官网
  • 网络推广协议磐石网站seo
  • 网站页面链接怎么做百度入驻
  • 提升网站排名网络营销的方式有十种
  • 河北城乡建设官方网站营销型网站策划
  • 山东外贸国际网站建设bittorrentkitty磁力猫
  • 网站如何做301关系网站优化公司
  • 做网站技术含量百度一下官方网
  • 西安做网站哪家便宜私人浏览器