虚拟DOM

React通过虚拟DOM提高页面性能,避免频繁DOM操作导致的性能下降。虚拟DOM是一种JS对象,用于描述真实DOM并进行高效更新。当数据变化时,React使用diff算法比较新旧虚拟DOM,找出最小修改路径,减少DOM操作次数和范围,实现跨端应用。然而,虚拟DOM也存在额外的创建函数开销,但JSX语法可以简化这一过程。

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

React框架的核心优势之一, 就是支持创建虚拟DOM来提高页面性能。那么, 什么是虚拟DOM呢?其实, 虚拟DOM这个概念很早就被提出来了, 是相对于实际DOM而言的。
设计人员在设计传统HTML网页的UI时, 都会在页面中定义若干的DOM元素, 这些DOM元素是所谓的实际DOM。通常, 页面中的实际DOM负责承载着外观表现和数据变化,任何外观形式的改变或数据信息的更新都要反馈到UI上, 都是需要通过操作实际DOM来实现的。
于是, 问题也就自然出现了。对于复杂的页面UI而言, 往往会定义大量的实际DOM。频繁地操作大量实际DOM, 往往会带来访问性能的严重下降, 用户体验也会随之变差, 这些都是设计人员所不希望看到的。因此, React框架专门针对这个现象引入了虚拟DOM机制,以避免频繁的DOM操作带来的性能下降问题。
React DOM类似于一种将相关的实际DOM组合在一起的集合, 是有区别于传统概念上的DOM元素的,如果将其理解为DOM组件应该更为贴切。因此,React框架将ReactDOM称为虚拟DOM

实际DOM的构建

<body>
    <div id="id-div">

    </div>

    <script type="text/javascript">
        //定位到div
        const divDom = document.getElementById('id-div');
        //创建DOM控件
        const jsSpan = document.createElement('span');
        const jsH3 = document.createElement('h3');
        jsH3.innerText = '实际的DOM';
        const jsP = document.createElement('p');
        jsP.innerText = 'DOM1';

        jsSpan.appendChild(jsH3);
        jsSpan.appendChild(jsP);

        divDom.appendChild(jsSpan)
    </script>
</body>

实现效果:
在这里插入图片描述
在这里插入图片描述

生成过程:

  1. 数据
  2. 模版
  3. 数据+模版结合,生成真实的DOM,来显示
  4. 数据发生改变
  5. 数据+模版结合,生成真实的DOM,替换原始的DOM

当p标签中内容DOM1改变为DOM2时,实际上是重新构建了DOM树进行替换,极大的增加了消耗
在这里插入图片描述

缺陷:

  • 第一次生成了一个完整的DOM片段
  • 第二次生成了一个完整的DOM片段
  • 第二次的DOM替换第一次的DOM,非常耗性能

虚拟DOM的构建

<body>
    <div id="example"></div>

    <script type="text/babel">
        const divReact = document.getElementById('example');

        const reactH3 = React.createElement('h3', {}, '虚拟的DOM');
        const reactP = React.createElement('p', {}, 'DOM3');
        const reactSpan = React.createElement('span', {}, reactH3, reactP);

        ReactDOM.render(reactSpan, divReact);
    </script>
</body>

在这里插入图片描述

JSX语法

<body>

    <div id="react-div"></div>
    <script type="text/babel">
        const reactDiv = document.getElementById('react-div');

        const reactSpan = (
            <span>
                <h3>JSX语法</h3>
            </span>
        );
        ReactDOM.render(reactSpan, reactDiv);

    </script>
</body>
  1. state数据
  2. JSX模版
  3. 数据+模版生成虚拟DOM(虚拟DOM就是一个JS对象,用它来描述真实DOM)(损耗了性能)[ 'div' , {id: 'abc'}, [ 'span', {}, 'hello world']]
  4. 用虚拟DOM的结构生成真实的DOM,来显示<div id='abc'><span>hello world</span></div>
  5. state 发生变化
  6. 数据+模版生成新的虚拟DOM(极大的提升了性能)[ 'div', {id: 'abc'}, [ 'span' , {},'bye bye' ]]
  7. 比较原始虚拟DOM和新的虚拟DOM的区别,找到区别是span中内容(极大的提升性能)
  8. 直接操作DOM,改变span中的内容

DOM生成过程

JSX -->createElement -->虚拟DOM (JS 对象)–>真实的DOM

虚拟DOM中的diff

在实际的代码中,会对新旧两棵树进行一个深度优先的遍历,这样每个节点都会有一个唯一的标记。在深度优先遍历的时候,每遍历到一个节点就把该节点和新的的树进行对比。如果有差异的话就记录到一个对象里面。

diff算法中只会比较同层级的元素,一旦发现某一级别之间有所不同,则会弃置其子级,直接用新的差异的一级以及其下的所有子级替换老的。 好处:算法简单,也就提高了比对速度,因此最后也就提升了性能。

关于DOM的误区

有些人认为DOM操作慢,虚拟 DOM快。
这句话类似于:刘翔矮(对比于姚明)。
DOM操作慢是对比于JS原生API,如数组操作。
任何基于DOM的库(Vue/React)都不可能在操作DOM时比 DOM快。

只有在以下情况虚拟DOM是比DOM快的:
虚拟DOM可以将多次操作合并为一次操作。
虚拟DOM借助DOM diff可以把多余的操作省掉。

虚拟DOM优点

1. 性能提升了。
减少DOM操作次数:
虚拟DOM可以将多次操作合并为一次操作。当你在一次操作时,需要更新10个DOM节点,浏览器没这么智能,收到第一个更新DOM请求后,并不知道后续还有9次更新操作,因此会马上执行流程,最终执行10次流程。比如想添加1000个节点,本来应该是一个接一个操作,虚拟DOM只用操作一次
减少DOM操作范围:
虚拟DOM借助DOM diff可以把多余的操作省掉。更新10个DOM节点,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地的一个js对象中,最终将这个js对象一次性attach到DOM树上,避免大量的无谓计算。比如想添加100个节点,发现本来页面上有需要的90个节点,其实只有10个是更新后新增的,不用再去操作剩余的90个节点。

2. 使得跨端应用得以实现。React Native
虚拟 DOM 最大的优势在于抽象了原本的渲染过程,实现了跨平台的能力,而不仅仅局限于浏览器的 DOM,可以是安卓和 IOS 的原生组件,可以是近期很火热的小程序,也可以是各种GUI,因为虚拟DOM本质上只是一个JS对象。

虚拟DOM缺点

需要额外的创建函数,如createElement,但可以通过JSX来简化成XML写法

React.createElement(‘li’,{onClick:this.addList.bind(this)},`${你好}`)

JSX语法:通过babel转为createElement形式

<li onClick={this.addList}>你好</li>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值