Vue虚拟DOM有什么用

2022/4/27 面试web前端

# DOM的增删改

用我们传统的开发模式,原生JS或JQ操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍流程。在一次操作中,我需要更新10个DOM节点,浏览器收到第一个DOM请求后并不知道还有9次更新操作,因此会马上执行流程,最终执行10次。例如,第一次计算完,紧接着下一个DOM更新请求,这个节点的坐标值就变了,前一次计算为无用功。计算DOM节点坐标值等都是白白浪费的性能。即使计算机硬件一直在迭代更新,操作DOM的代价仍旧是昂贵的,频繁操作还是会出现页面卡顿,影响用户体验。

# 为什么需要虚拟DOM

Web界面由DOM树(树的意思是数据结构)来构建,当其中一部分发生变化时,其实就是对应某个DOM节点发生了变化,虚拟DOM就是为了解决浏览器性能问题而被设计出来的。如前,若一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量。所以,用JS对象模拟DOM节点的好处是,页面的更新可以先全部反映在JS对象(虚拟DOM)上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制。

# 什么是Diff

那么diff是什么呢?其实,diff 在我们计算机中就是代表着最小量更新的一个算法,会进行精细化对比,以最小量去更新。这样你就会发现,它的代价比较小,也不会昂贵,也会比较优化,所以对应在我们 Vue底层中是非常关键的。 好了,现在回归到我们的Vue中,上面的户型图中就相当于vue中的 DOM节点,我们需要对这些节点进行改造(增删调),然后以最小量去更新DOM,这样就会避免我们性能上面的开销。

# 虚拟DOM是什么

<div class="box">
        <h2>标题</h2>
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
        </ul>
    </div>
1
2
3
4
5
6
7
8
{
    sel: "div",
    elm: undefined, // 表示虚拟节点还没有上树
    key: undefined, // 唯一标识
    data: {
        class: { "box" : true}
    },
    children: [
        {
            sel: "h2",
            data: {},
            text: "标题"
        },
        {
            sel: "ul",
            data: {},
            children: [
                { sel: li, data: {}, text: "1"},
                { sel: li, data: {}, text: "2"},
                { sel: li, data: {}, text: "3"}
            ]
        }
    ]
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

通过观察可以发现,虚拟DOM 是一个 JavsScript对象,里面包含 sel选择器data数据text文本内容children子标签等等,一层嵌套一层。这样就表达了一个虚拟DOM结构,处理 虚拟DOM 的方式总比处理 真实的DOM 要简单并且高效,所以 diff算法 是发生在 虚拟DOM上的。 注意:diff算法 是发生在虚拟DOM上的。

# Diff算法

  1. key 是当前节点的唯一标识,告诉 diff算法,在更改前后它们是同一个 DOM节点
  2. 只有是同一个虚拟节点diff算法 才进行精细化比较,否则就是暴力删除旧的、插入新的。判断同一个虚拟节点的依据:选择器(sel)相同key相同
  3. diff算法 只进行同层比较,不会进行跨层比较。即使是同一片虚拟节点,但是跨层了,不进行精细化比较,而是暴力删除旧的、然后插入新的。

# Vue中的虚拟DOM

170b414d73437744_tplv-t2oaga2asx-zoom-in-crop-mark_1304_0_0_0

渲染函数:渲染函数是用来生成虚拟DOM的。Vue推荐使用模板来构建应用界面,在底层实现中Vue将模板编译成渲染函数。

Vnode虚拟节点:它可以代表一个真实的dom节点。通过createElement方法将vnode节点渲染成dom节点。

patch:虚拟DOM最核心的部分,它可以将vnode渲染成真实的DOM,这个过程是对比新旧虚拟节点之间有哪些不同,然后根据对比结果找出需要更新的的节点进行更新

# 个人理解

Vue将模版编译成渲染函数,渲染函数执行后生成模版对应的虚拟节点vnode,vnode是js对象,存储着信息,通过patch可以将虚拟节点转成浏览器DOM。patch过程是使用diff算法比较新旧vnode找出最优的修改方式保证最少的修改。patch是一个边比对边打补丁的方式,最终通过DOM fragment操作给浏览器渲染。

Diff算法只是为了虚拟DOM比较替换效率更高,通过Diff算法得到diff算法结果数据表(需要进行哪些操作记录表)。原本要操作的DOM在vue这边还是要操作的,只不过用到了js的DOM fragment来操作dom(统一计算出所有变化后统一更新一次DOM)进行浏览器DOM一次性更新。其实DOM fragment我们不用平时发开也能用,但是这样程序员写业务代码就用把DOM操作放到fragment里,这就是框架的价值,程序员才能专注于写业务代码。

Last Updated: 2022/4/27 23:51:19