虚拟dom-Diff算法

虚拟dom-Diff算法

vue2

diff算法在vue2中就是patch,通过新旧虚拟dom对比,找到最小变化然后进行dom操作
在页面首次渲染的时候会调用一次patch并创建新的vnode,不会进行深层次的比较,然后再组件中数据发生变化的时候,会触发setter然后通过notify通知watcher,对应的watcher会通知更新并执行更新函数,会执行render函数获取新的虚拟dom,然后执行patch对比上次渲染结果的老的dom,计算出最小的变化,根据最小的变化去更新真实的dom

什么是diff算法

diff是新旧内容之间的区别经计算,vue中的diff算法,就是通过一种简单而且高效的手段对比出新旧节点数组之间的区别以便以最小的dom操作来更新页面内容

  • 对比的是vnode数组
  • 同时存在新旧两组vnode数组
    真实的dom节点都是树的形式存在的,根节点都是, 为了保证虚拟节点能和真实dom节点一样,vnode也采用树形结构
    如果再组件更新的时候,需要对比全部vnode节点的话,新旧两组节点需要及进行深度遍历和比较,会产生很大的性能开销,所以,vue中默认同层节点比较,多余层级的内容会直接新建或者舍弃,只再同层级进行diff操作
    一般来说,diff操作一般发生在v-for循环或者有v-if/v-else,component这类动态生成的节点对象上

diff算法的优化

只会对比同一层级,不会跨级比较

在这里插入图片描述

比较标签名

如果同一层级的比较标签名不同,旧直接移除老的虚拟节点
在这里插入图片描述

比较key

从标签名相同,key相同,就会被认为是相同节点,也不继续按照这个树状结果做深度比较,比如写v-for的时候会比较key,不写key就会报错
在这里插入图片描述

在不使用key或者列表的index作为key的时候,每个元素对应的位置关系都是index,如果没有key的话,后续的li都会重新渲染。如果使用key的话,后续会判断li3和li4没有发生变化,所以不会重新渲染。

  • key的作用是为了更加搞笑的更新虚拟dom,因为可以非常精确的找到相同节点
  • vue在patch过程中会判断两个节点是不是相同节点,key是一个必要条件。如果在渲染列表的时候,不写key,vue在比较的时候,导致频繁更新元素,使得整个patch比较低效
  • 避免使用数组下标作为key,因为key值不是唯一的话,可能导致出现上图的bug。
  • vue判断两个节点是否相同的时候需要主动判断两者的元素类型和key,如果不设置key,就可能被认为两个相同的节点,只能做更新操作,造成大量不必要的dom更新操作。

双端diff

简单diff算法: 通过暴力手段直接遍历两个数组。双端就是从两端开始分别从中间进行遍历对比的算法

  1. 新旧头相等
  2. 新旧尾相等
  3. 旧头等于新尾
  4. 旧尾等于新头
  5. 四者互不相等
新头旧尾

在这里插入图片描述

头头相等

在这里插入图片描述

尾尾比较

在这里插入图片描述

新尾旧头

在这里插入图片描述

循环比较

在这里插入图片描述

增删

循环没有找到

在这里插入图片描述

头头,尾尾,头尾, 尾头没有匹配到,然后循环遍历,如果循环遍历没有找到,则生成这个节点。

children内增加节点
头头

在这里插入图片描述

尾尾

在这里插入图片描述

children内减少节点

在这里插入图片描述

增加整个children

在这里插入图片描述

删除整个children

在这里插入图片描述

vue3

什么时候用到了diff算法

存在children的vnode类型,element类型中vnode中存在children
flagment碎片类型vnode,可以创建一个具有多个dom节点的组件的方法就是创建一个没有底层vue实例的功能组件

<template>
    <span>1</span>
    <span>2</span>
    <span>3</span>
</template>
// flagment出现就是看起来像一个普通的dom元素,但是是虚拟的,不会在dom树中呈现
<Fragment>
    <span>1</span>
    <span>2</span>
    <span>3</span>
</Fragment>

patchChildren根据是否存在key进行真正的diff或者直接patch

diff算法

头和头比
尾和尾比
基于最长递增子序列进行移动/添加/删除

先进行头和头比较,发现不同旧结束循环
然后进行尾和尾比较,发现不同就结束循环
在保存没有比较过的节点,并通过newIndexToOldIndexMap拿到数组里面对应的下标,生成数组,-1是老数组里没有的就是说明是新增
然后取出数组里面的最长递增子序列,
然后只需要把其他的剩余节点,基于最长子序列的位置进行移动新增和删除就可以了
比较新老children的length获取最小值,然后对于公共部分,重新进行patch工作
如果老节点数量大于新的节点数量,移除多出来的节点
如果新的节点数量大于老的节点数量,重新mountChildren新增的节点
在这里插入图片描述

在这里插入图片描述

如果老节点是否全部patch,新节点没有被patch完,创建新的vnode
如果新节点全部被patch,老节点有剩余,那么卸载所有老节点

最长子序列

这个核心,后续回写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值