电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

詳解Vue2的diff算法

瀏覽:36日期:2022-10-12 13:21:16
前言

雙端比較算法是vue2.x采用的diff算法,本篇文章只是對雙端比較算法粗略的過程進行了一下分析,具體細節還是得Vue源碼,Vue的源碼在這

過程

假設當前有兩個數組arr1和arr2

let arr1 = [1,2,3,4,5]let arr2 = [4,3,5,1,2]

那么其過程有五步

arr1[0] 和 arr2[0]比較 arr1[ arr1.length-1 ] 和 arr2[ arr2.length-1 ] 比較 arr1[0] 和 arr2[ arr2.length-1 ] 比較 arr1[ arr1.length-1 ] 和 arr2[0] 比較 arr2[0] 和 arr1的每個元素進行比較

每次比較都是從數組的兩端開始比較,如果是首位比較相等,那么比較的開頭索引+1

如果是在末尾比較成功,那么比較的結束索引-1,當開頭索引大于結束索引時說明比較已經結束

拆解過程

let arr1 = [1,2,3,4,5]let arr2 = [4,3,5,1,2]let oldStartIdx = 0 let oldEndIdx = arr1.lenght -1let newStartIdx = 0let newEndIdx = arr2.length -1let oldStartVNode = arr1[oldStartIdx] let oldEndVNode = arr1[oldEndIdx] let newStartVNode = arr2[newStartIdx] let newEndVNode = arr2[newEndIdx]第一輪: 1. 1和4比較不相等 2. 5和2比較不相等 3. 1和2比較不相等 4. 5和4比較不相等 5. 4和舊數組逐一比較,和索引為3的值相等,說明4由索引3變換位置為了0, newStartIdx++ //比較完后,使用u_1表示比較成功的元素 [1,2,3,u_1,5] //arr1 [u_1,3,5,1,2] //arr2第二輪: 1. 1和3比較不相等 2. 5和2比較不相等 3. 1和2比較不相等 4. 5和3比較不相等 5. 3和舊數組逐一比較,和索引為2的值相等,3由索引2變換位置為了0, newStartIdx++ //比較成功后,使用u_2表示比較成功的元素 [1,2,u_2,u_1,5] //arr1 [u_1,u_2,5,1,2] //arr2第三輪: 1. 1和5比較不相等 2. 5和2比較不相等 3. 1和2比較不相等 4. 5和5比較相等,5已經從舊數組oldEndIdx位置移動到了newStartIdx位置,newStartIdx++, oldEndIdx-- 5. 第四步比較成功,進入下一輪 //比較成功后,使用u_3表示比較成功的元素 [1,2,u_2,u_1,u_3] //arr1 [u_1,u_2,u_3,1,2] //arr2第四輪: 1. 1和1比較相等,1已經從舊數組oldStartIdx位置移動到newStartIdx位置,oldStartIdx++,newStartIdx++ 2. 第一步比較成功,進入下一輪 3. 第一步比較成功,進入下一輪 4. 第一步比較成功,進入下一輪 5. 第一步比較成功,進入下一輪 //比較成功后,使用u_4表示比較成功的元素 [u_4,2,u_2,u_1,u_3] //arr1 [u_1,u_2,u_3,u_4,2] //arr2第五輪: 1. 2和2比較相等,1已經從舊數組oldStartIdx位置移動到newStartIdx位置,oldStartIdx++,newStartIdx++ 2. 第一步比較成功,進入下一輪 3. 第一步比較成功,進入下一輪 4. 第一步比較成功,進入下一輪 5. 第一步比較成功,進入下一輪 //比較成功后,使用u_5表示比較成功的元素 [u_4,u_5,u_2,u_1,u_3] //arr1 [u_1,u_2,u_3,u_4,u_5] //arr2

用一個gif圖來表示

詳解Vue2的diff算法

上代碼

function diff(prevChildren, nextChildren) { let oldStartIdx = 0 //舊數組起始索引 let oldEndIdx = prevChildren.length - 1 //舊數組結束索引 let newStartIdx = 0 //新數組其實索引 let newEndIdx = nextChildren.length - 1 //新數組結束索引 let oldStartVNode = prevChildren[oldStartIdx] let oldEndVNode = prevChildren[oldEndIdx] let newStartVNode = nextChildren[newStartIdx] let newEndVNode = nextChildren[newEndIdx] while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) { if (!oldStartVNode) { //undefined 時前移一位 oldStartVNode = prevChildren[++oldStartIdx] } else if (!oldEndVNode) { //undefined 時后移一位 oldEndVNode = prevChildren[--oldEndIdx] } else if (oldStartVNode.key === newStartVNode.key ) { //1.開始與開始 oldStartVNode = prevChildren[++oldStartIdx] newStartVNode = nextChildren[++newStartIdx] } else if ( oldEndVNode.key === newEndVNode.key ) { //2.結束與結束 oldEndVNode = prevChildren[--oldEndIdx] newEndVNode = nextChildren[--newEndIdx] } else if (oldStartVNode.key === newEndVNode.key ) { //3.開始與結束 oldStartVNode = prevChildren[++oldStartIdx] newEndVNode = nextChildren[--newEndIdx] } else if (oldEndVNode.key === newStartVNode.key ) { //4.結束與開始 oldEndVNode = prevChildren[--oldEndIdx] newStartVNode = nextChildren[++newStartIdx] } else { //5.新數組開頭元素和舊數組每一個元素對比 const idxInOld = prevChildren.findIndex((node) => {if (node && node.key === newStartVNode.key) { return true} }) if (idxInOld >= 0) {prevChildren[idxInOld] = undefined } else {//newStartVNode是新元素 } newStartVNode = nextChildren[++newStartIdx] } } }diff([1,2,3,4,5],[4,3,5,1,2])

我們發現,上面的算法走完后,如果新舊兩個數組只是順序變化,那么它能完美的diff出差異,但是如果新數組有新增或者刪除的時候就不行了,因此我們在while循環完成后需要找出新增或者刪除的元素,那怎么知道哪些是新增哪些是刪除的元素呢?

在比較的第五步,選取的新數組的第一個元素和舊數組的所有元素逐一對比,這里我們就可以得出了這個數組是否是新增,如果對比相等,那就是位置變換,否則當前元素就是新增的,但是,while循環的條件是oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx,如果是以下情況

let arr1 = [1,2,3,4,5]let arr2 = [1,2,3,4,5,6,7]

因為循環條件的導致,這里會在5次while后就結束了,因此在數組末尾的6和7永遠走不了第五步的插入條件,那如何判斷6和7是新增的呢?我們來觀察一下while循環結束后的索引

//例子1let arr1 = [1,2,3,4,5]let arr2 = [1,2,3,4,5,6,7]//diff后它們的索引為oldStartIdx = 5, oldEndIdx = 4newStartIdx = 5, newEndIdx = 6//例子2let arr1 = [1,2,3,4,5]let arr2 = [4,5,6,7,1,3,2]//diff后它們的索引為oldStartIdx = 3, oldEndIdx = 2newStartIdx = 6, newEndIdx = 5//例子3let arr1 = [1,2,3,4,5]let arr2 = [7,1,3,5,6,4,2]//diff后它們的索引為oldStartIdx = 5, oldEndIdx = 4newStartIdx = 4, newEndIdx = 4//例子4let arr1 = [1,2,3,4,5]let arr2 = [2,4,1,5,7,3,6]//diff后它們的索引為oldStartIdx = 3, oldEndIdx = 2newStartIdx = 6, newEndIdx = 6

我們發現,新增元素的索引和newStartIdx還有newEndIdx是一一對應的

例子1:newStartIdx小于newEndIdx,并且是5和6,而新增元素6對應在arr2的索引為6,新增元素7對應在arr2的索引為7,此時6和7都已經越界出arr1的長度范圍 例子2:newStartIdx是大于newEndIdx,沒有對應關系 例子3:newStartIdx等于newEndIdx,我們發現arr2索引為4的元素正是新增元素6,但是6次時沒有越界出arr1的長度范圍,它剛好在數組的最后一個元素 例子4:newStartIdx等于newEndIdx,arr2中索引為6的值正是新增元素6

那么得出的結論就是,如果在while循環結束后,如果newStartIdx是小于或者等于newEndIdx,那么在newStartIdx和newEndIdx索引之間對應的元素就是新增的元素,并且oldStartIdx總是比oldEndIdx大

上面說完了新增,那如果是刪除元素呢?看例子

//例子1let arr1 = [4,3,5,6,7,2,1]let arr2 = [1,3,5,4,2]//diff后它們的索引為oldStartIdx = 3, oldEndIdx = 4newStartIdx = 3, newStartIdx = 2//例子2let arr1 = [7,2,3,5,6,1,4]let arr2 = [5,1,2,3,4]//diff后它們的索引為oldStartIdx = 0, oldEndIdx = 4newStartIdx = 4, newStartIdx = 3//例子3let arr1 = [1,5,4,2,6,7,3]let arr2 = [4,5,1,2,3]//diff后它們的索引為oldStartIdx = 4, oldEndIdx = 5newStartIdx = 4, newStartIdx = 3

同理新增的觀察套路,發現newStartIdx總是比newStartIdx大,并且需要刪除的元素總是在oldStartIdx和oldEndIdx對應的索引之間,那么我們只需要把oldStartIdx和oldEndIdx的元素刪除即可,那問題來了,像例子2 中oldStartIdx和oldEndIdx索引之間的元素有7,2,3,5,6其中真正需要刪除的只有7和6,這樣子不就誤刪了2,3,5么?關鍵的來了,我們看例子2的2,3,5發現它們走的都是雙端比較算法的第五步,第五步寫的代碼是

const idxInOld = prevChildren.findIndex((node) => { if (node && node.key === newStartVNode.key) { return true } }) if (idxInOld >= 0) { prevChildren[idxInOld] = undefined } else { //newStartVNode是新元素 } newStartVNode = nextChildren[++newStartIdx]

如果idxInOld>0說明在舊數組中找到了,那么我們將preChildren[idxInOld]設置為undefined,也就是說2,3,5經過diff算法后,它們在arr1中的值已經被替換為了undefined,這里也是就為什么在diff算法開始需要判斷!oldStartVNode和!oldEndVnode的原因了,下面我們完善代碼

function diff(prevChildren, nextChildren) { let oldStartIdx = 0 //舊數組起始索引 let oldEndIdx = prevChildren.length - 1 //舊數組結束索引 let newStartIdx = 0 //新數組其實索引 let newEndIdx = nextChildren.length - 1 //新數組結束索引 let oldStartVNode = prevChildren[oldStartIdx] let oldEndVNode = prevChildren[oldEndIdx] let newStartVNode = nextChildren[newStartIdx] let newEndVNode = nextChildren[newEndIdx] while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) { if (!oldStartVNode) { //undefined 時前移一位 oldStartVNode = prevChildren[++oldStartIdx] } else if (!oldEndVNode) { //undefined 時后移一位 oldEndVNode = prevChildren[--oldEndIdx] } else if (oldStartVNode.key === newStartVNode.key ) { //1.開始與開始 oldStartVNode = prevChildren[++oldStartIdx] newStartVNode = nextChildren[++newStartIdx] } else if ( oldEndVNode.key === newEndVNode.key ) { //2.結束與結束 oldEndVNode = prevChildren[--oldEndIdx] newEndVNode = nextChildren[--newEndIdx] } else if (oldStartVNode.key === newEndVNode.key ) { //3.開始與結束 oldStartVNode = prevChildren[++oldStartIdx] newEndVNode = nextChildren[--newEndIdx] } else if (oldEndVNode.key === newStartVNode.key ) { //4.結束與開始 oldEndVNode = prevChildren[--oldEndIdx] newStartVNode = nextChildren[++newStartIdx] } else { //5.新數組開頭元素和舊數組每一個元素對比 const idxInOld = prevChildren.findIndex((node) => {if (node && node.key === newStartVNode.key) { return true} }) if (idxInOld >= 0) {prevChildren[idxInOld] = undefined } else {//newStartVNode是新元素 } newStartVNode = nextChildren[++newStartIdx] } } if (oldStartIdx > oldEndIdx) { for (; newStartIdx <= newEndIdx; ++newStartIdx) { //新增內容 let vnode = nextChildren[newStartIdx] } } else if (newStartIdx > newEndIdx) { for (let i = oldStartIdx; i <= oldEndIdx; i++) { / /刪除內容 } }}diff([1,2,3,4,5],[4,3,5,1,2])

接下來我們使用兩個gif圖來表示一下diff過程

1.新增元素

詳解Vue2的diff算法

2.減少元素

詳解Vue2的diff算法

以上就是詳解Vue2的diff算法的詳細內容,更多關于Vue2的diff算法的資料請關注好吧啦網其它相關文章!

標簽: Vue
相關文章:
主站蜘蛛池模板: 恒温恒湿试验箱_高低温试验箱_恒温恒湿箱-东莞市高天试验设备有限公司 | 磁力加热搅拌器-多工位|大功率|数显恒温磁力搅拌器-司乐仪器官网 | 电动垃圾车,垃圾清运车-江苏速利达机车有限公司 | 称重传感器,测力传感器,拉压力传感器,压力变送器,扭矩传感器,南京凯基特电气有限公司 | 琉璃瓦-琉璃瓦厂家-安徽盛阳新型建材科技有限公司 | 洗地机_全自动洗地机_手推式洗地机【上海滢皓环保】 | 压缩空气冷冻式干燥机_吸附式干燥机_吸干机_沪盛冷干机 | 济宁工业提升门|济宁电动防火门|济宁快速堆积门-济宁市统一电动门有限公司 | 不锈钢管件(不锈钢弯头,不锈钢三通,不锈钢大小头),不锈钢法兰「厂家」-浙江志通管阀 | 电位器_轻触开关_USB连接器_广东精密龙电子科技有限公司 | 刑事律师_深圳著名刑事辩护律师_王平聚【清华博士|刑法教授】 | 智能风向风速仪,风速告警仪,数字温湿仪,综合气象仪(气象五要素)-上海风云气象仪器有限公司 | Q361F全焊接球阀,200X减压稳压阀,ZJHP气动单座调节阀-上海戎钛 | 万博士范文网-您身边的范文参考网站Vanbs.com| 电车线(用于供电给电车的输电线路)-百科 | 仿清水混凝土_清水混凝土装修_施工_修饰_保护剂_修补_清水混凝土修复-德州忠岭建筑装饰工程 | 碳刷_刷握_集电环_恒压簧_电刷厂家-上海丹臻机电科技有限公司 | EDLC超级法拉电容器_LIC锂离子超级电容_超级电容模组_软包单体电容电池_轴向薄膜电力电容器_深圳佳名兴电容有限公司_JMX专注中高端品牌电容生产厂家 | 暖气片十大品牌厂家_铜铝复合暖气片厂家_暖气片什么牌子好_欣鑫达散热器 | 成都顶呱呱信息技术有限公司-贷款_个人贷款_银行贷款在线申请 - 成都贷款公司 | 浇注料-高铝砖耐火砖-郑州凯瑞得窑炉耐火材料有限公司 | 变压器配件,变压器吸湿器,武强县吉口变压器配件有限公司 | pH污水传感器电极,溶解氧电极传感器-上海科蓝仪表科技有限公司 | 棉柔巾代加工_洗脸巾oem_一次性毛巾_浴巾生产厂家-杭州禾壹卫品科技有限公司 | 劳动法网-专业的劳动法和劳动争议仲裁服务网 | 示波器高压差分探头-国产电流探头厂家-南京桑润斯电子科技有限公司 | 水平筛厂家-三轴椭圆水平振动筛-泥沙震动筛设备_山东奥凯诺矿机 包装设计公司,产品包装设计|包装制作,包装盒定制厂家-汇包装【官方网站】 | 泥浆在线密度计厂家-防爆数字压力表-膜盒-远传压力表厂家-江苏大亚自控设备有限公司 | 台式核磁共振仪,玻璃软化点测定仪,旋转高温粘度计,测温锥和测温块-上海麟文仪器 | 铝合金线槽_铝型材加工_空调挡水板厂家-江阴炜福金属制品有限公司 | 本安接线盒-本安电路用接线盒-本安分线盒-矿用电话接线盒-JHH生产厂家-宁波龙亿电子科技有限公司 | 烟气换热器_GGH烟气换热器_空气预热器_高温气气换热器-青岛康景辉 | 广西资质代办_建筑资质代办_南宁资质代办理_新办、增项、升级-正明集团 | OLChemim试剂-ABsciex耗材-广州市自力色谱科仪有限公司 | 洛阳网站建设_洛阳网站优化_网站建设平台_洛阳香河网络科技有限公司 | 安徽控制器-合肥船用空调控制器-合肥家电控制器-合肥迅驰电子厂 安徽净化板_合肥岩棉板厂家_玻镁板厂家_安徽科艺美洁净科技有限公司 | 北京公寓出租网-北京酒店式公寓出租平台 | 缠绕机|缠绕膜包装机|缠绕包装机-上海晏陵智能设备有限公司 | 上海阳光泵业制造有限公司 -【官方网站】 | 仪器仪表网 - 永久免费的b2b电子商务平台 | 雷蒙磨,雷蒙磨粉机,雷蒙磨机 - 巩义市大峪沟高峰机械厂 |