15张图,20分钟吃透Diff算法核心原理,我说的!!!

本文通俗讲解了虚拟DOM的概念,以及Diff算法在对比新旧虚拟DOM时如何精确更新真实DOM,从而优化性能。通过实例分析了Diff算法的工作原理,包括广度优先的同层比较和关键的patch方法,以及为何使用唯一key避免DOM频繁更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言
大家好,我是林三心,在日常面试中,Diff算法都是绕不过去的一道坎,用最通俗的话,讲最难的知识点一直是我写文章的宗旨,今天我就用通俗的方式来讲解一下Diff算法吧?Lets Go
在这里插入图片描述

什么是虚拟DOM
讲Diff算法前,我先给大家讲一讲什么是虚拟DOM吧。这有利于后面大家对Diff算法的理解加深。
虚拟DOM是一个对象,一个什么样的对象呢?一个用来表示真实DOM的对

象,要记住这句话。我举个例子,请看以下真实DOM:
<ul id="list">
    <li class="item">哈哈</li>
    <li class="item">呵呵</li>
    <li class="item">嘿嘿</li>
</ul>
复制代码

对应的虚拟DOM为:

let oldVDOM = {
    // 旧虚拟DOM
        tagName: 'ul', // 标签名
        props: {
    // 标签属性
            id: 'list'
        },
        children: [ // 标签子节点
            {
   
                tagName: 'li', props: {
    class: 'item' }, children: ['哈哈']
            },
            {
   
                tagName: 'li', props: {
    class: 'item' }, children: ['呵呵']
            },
            {
   
                tagName: 'li', props: {
    class: 'item' }, children: ['嘿嘿']
            },
        ]
    }
复制代码

这时候,我修改一个li标签的文本:

<ul id="list">
    <li class="item">哈哈</li>
    <li class="item">呵呵</li>
    <li class="item">林三心哈哈哈哈哈</li> // 修改
</ul>
复制代码

这时候生成的新虚拟DOM为:

let newVDOM = {
    // 新虚拟DOM
        tagName: 'ul', // 标签名
        props: {
    // 标签属性
            id: 'list'
        },
        children: [ // 标签子节点
            {
   
                tagName: 'li', props: {
    class: 'item' }, children: ['哈哈']
            },
            {
   
                tagName: 'li', props: {
    class: 'item' }, children: ['呵呵']
            },
            {
   
                tagName: 'li', props: {
    class: 'item' }, children: ['林三心哈哈哈哈哈']
            },
        ]
    }
复制代码

这就是咱们平常说的新旧两个虚拟DOM,这个时候的新虚拟DOM是数据的最新状态,那么我们直接拿新虚拟DOM去渲染成真实DOM的话,效率真的会比直接操作真实DOM高吗?那肯定是不会的,看下图:
在这里插入图片描述

由上图,一看便知,肯定是第2种方式比较快,因为第1种方式中间还夹着一个虚拟DOM的步骤,所以虚拟DOM比真实DOM快这句话其实是错的,或者说是不严谨的。那正确的说法是什么呢?虚拟DOM算法操作真实DOM,性能高于直接操作真实DOM,虚拟DOM和虚拟DOM算法是两种概念。虚拟DOM算法 = 虚拟DOM + Diff算法
什么是Diff算法
上面咱们说了虚拟DOM,也知道了只有虚拟DOM + Diff算法才能真正的提高性能,那讲完虚拟DOM,我们再来讲讲Diff算法吧,还是上面的例子(这张图被压缩的有点小,大家可以打开看,比较清晰):
在这里插入图片描述

上图中,其实只有一个li标签修改了文本,其他都是不变的,所以没必要所有的节点都要更新,只更新这个li标签就行,Diff算法就是查出这个li标签的算法。
总结:Diff算法是一种对比算法。对比两者是旧虚拟DOM和新虚拟DOM,对比出是哪个虚拟节点更改了,找出这个虚拟节点,并只更新这个虚拟节点所对应的真实节点,而不用更新其他数据没发生改变的节点,实现精准地更新真实DOM,进而提高效率。
使用虚拟DOM算法的损耗计算:
总损耗 = 虚拟DOM增删改+(与Diff算法效率有关)真实DOM差异增删改+(较少的节点)排版与重绘
直接操作真实DOM的损耗计算:
总损耗 = 真实DOM完全增删改+(可能较多的节点)排版与重绘
Diff算法的原理
Diff同层对比
新旧虚拟DOM对比的时候,Diff算法比较只会在同层级进行, 不会跨层级比较。 所以Diff算法是:广度优先算法。 时间复杂度:O(n)
在这里插入图片描述

Diff对比流程
当数据改变时,会触发setter,并且通过Dep.notify去通知所有订阅者Watcher,订阅者们就会调用patch方法,给真实DOM打补丁,更新相应的视图。对于这一步不太了解的可以看一下我之前写Vue源码系列
newVnode和oldVnode:同层的新旧虚拟节点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CRMEB定制开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值