React 第三十二章 虚拟DOM

news2025/1/22 20:55:11

面试题:什么是虚拟DOM?其优点有哪些?
标准且浅显的答案
虚拟dom本质上就是一个普通的 JS 对象,用于描述视图的界面结构

虚拟 DOM 最早是由 React 团队提出来的,因此 React 团队在对虚拟 DOM 的定义上面有绝对的话语权。可以参考https://legacy.reactjs.org/docs/faq-internals.html

Virtual DOM 是一种编程概念 。在这个概念里, UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中。

也就是说,只要我们有一种方式,能够将真实 DOM 的层次结构描述出来,那么这就是一个虚拟 DOM。

image-20230223114000816

在 React 中,React 团队使用的是 JS 对象来对 DOM 结构进行一个描述。但是很多人会直接把 JS 对象和虚拟 DOM 划等号,这种理解是不太准确的,比较片面的。

虚拟 DOM 和 JS 对象之间的关系:前者是一种思想,后者是一种思想的具体实现。

为什么需要虚拟 DOM

使用虚拟 DOM 主要有两个方面的优势:

  • 相较于 DOM 的体积优势和速度优势
  • 多平台的渲染抽象能力

相较于 DOM 的体积优势和速度优势

首先我们需要明确一个点,JS 层面的计算速度要比 DOM 层面的计算要快:

  • DOM 对象最终要被浏览器渲染出来之前,浏览器会有很多工作要做(浏览器的渲染原理)
  • DOM 对象上面的属性也非常非常多
const div = document.createElement("div");
for(let i in div){console.log(i + " ")}

操作 JS 对象的时间和操作 DOM 对象的时间是完全不一样的。

JS 层面的计算速度要高于 DOM 层面的计算速度。

此时有一个问题:虽然使用了 JS 对象来描述 UI,但是最终不还是要用原生 DOM API 去操作 DOM 么?

虚拟 DOM 在第一次渲染页面的时候,并没有什么优势,速度肯定比直接操作原生 DOM API 要慢一些,虚拟 DOM 真正体现优势是在更新阶段。

根据 React 团队的研究,在渲染页面时,相比使用原生 DOM API,开发人员更加倾向于使用 innerHTML

let newP = document.createElement("p");
let newContent = document.createTextNode("this is a test");
newP.appendChild(newContent);
document.body.appendChild(newP);
document.body.innerHTML = `
	<p>
		this is a test
	</p>
`;

因此在使用 innerHTML 的时候,就涉及到了两个层面的计算:

  • JS 层面:解析字符串
  • DOM 层面:创建对应的 DOM 节点

接下来我们加入虚拟 DOM 来进行对比:

innerHTML虚拟 DOM
JS 层面计算解析字符串创建 JS 对象
DOM 层面计算创建对应的 DOM 节点创建对应的 DOM 节点

虚拟 DOM 真正发挥威力的时候,是在更新阶段

innerHTML 进行更新的时候,要全部重新赋值,这意味着之前创建的 DOM 节点需要全部销毁掉,然后重新进行创建

但是虚拟 DOM 只需要更新必要的 DOM 节点即可

innerHTML虚拟 DOM
JS 层面计算解析字符串创建 JS 对象
DOM 层面计算销毁原来所有的 DOM 节点修改必要的 DOM 节点
DOM 层面计算创建对应的 DOM 节点

多平台的渲染抽象能力

UI = f(state)这个公式进一步进行拆分可以拆分成两步:

  • 根据自变量的变化计算出 UI
  • 根据 UI 变化执行具体的宿主环境的 API

虚拟 DOM 只是多真实 UI 的一个描述,回头根据不同的宿主环境,可以执行不同的渲染代码:

  • 浏览器、Node.js 宿主环境使用 ReactDOM 包
  • Native 宿主环境使用 ReactNative 包
  • Canvas、SVG 或者 VML(IE8)宿主环境使用 ReactArt 包
  • ReactTest 包用于渲染出 JS 对象,可以很方便地测试“不隶属于任何宿主环境的通用功能”

React 中的虚拟DOM

在 React 中通过 JSX 来描述 UI,JSX 最终会被转为一个叫做 createElement 方法的调用,调用该方法后就会得到虚拟 DOM 对象。

经过 Babel 编译后结果如下:

image-20221226155735808

在源码中 createElement 方法如下:

/**
 *
 * @param {*} type 元素类型 h1
 * @param {*} config 属性对象 {id : "aa"}
 * @param {*} children 子元素 hello
 * @returns
 * <h1 id="aa">hello</h1>
 */
export function createElement(type, config, children) {
  let propName;

  const props = {};

  let key = null;
  let ref = null;
  let self = null;
  let source = null;

  // 说明有属性
  if (config != null) {
    // ...
    for (propName in config) {
      if (
        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        props[propName] = config[propName];
      }
    }
  }
  // 经历了上面的 if 之后,所有的属性都放到了 props 对象上面
  // props ==> {id : "aa"}

  // children 可以有多个参数,这些参数被转移到新分配的 props 对象上
  // 如果是多个子元素,对应的是一个数组
  const childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    const childArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    // ...
    props.children = childArray;
  }

  // 添加默认的 props
  if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  // ...
  return ReactElement(
    type,
    key,
    ref,
    self,
    source,
    ReactCurrentOwner.current,
    props
  );
}

const ReactElement = function (type, key, ref, self, source, owner, props) {
    // 该对象就是最终向外部返回的 vdom(也就是用来描述 DOM 层次结构的 JS 对象)
  const element = {
    // 让我们能够唯一地将其标识为 React 元素
    $$typeof: REACT_ELEMENT_TYPE,

    // 元素的内置属性
    type: type,
    key: key,
    ref: ref,
    props: props,

    // 记录负责创建此元素的组件。
    _owner: owner,
  };
  // ...
  return element;
};

在上面的代码中,最终返回的 element 对象就是我们所说的虚拟 DOM 对象。在官方文档中,官方更倾向于将这个对象称之为 React 元素。

真题解答

题目:什么是虚拟DOM?其优点有哪些?

参考答案:

虚拟 DOM 最初是由 React 团队所提出的概念,这是一种编程的思想,指的是针对真实 UI DOM 的一种描述能力。

在 React 中,使用了 JS 对象来描述真实的 DOM 结构。虚拟DOM和 JS 对象之间的关系:前者是一种思想,后者是这种思想的具体实现。

使用虚拟 DOM 有如下的优点:

  • 相较于 DOM 的体积和速度优势
  • 多平台渲染的抽象能力

相较于 DOM 的体积和速度优势

  • JS 层面的计算的速度,要比 DOM 层面的计算快得多
    • DOM 对象最终要被浏览器显示出来之前,浏览器会有很多工作要做(浏览器渲染原理)
    • DOM 上面的属性也是非常多的
  • 虚拟 DOM 发挥优势的时机主要体现在更新的时候,相比较 innerHTML 要将已有的 DOM 节点全部销毁,虚拟 DOM 能够做到针对 DOM 节点做最小程度的修改

多平台渲染的抽象能力

  • 浏览器、Node.js 宿主环境使用 ReactDOM 包
  • Native 宿主环境使用 ReactNative 包
  • Canvas、SVG 或者 VML(IE8)宿主环境使用 ReactArt 包
  • ReactTest 包用于渲染出 JS 对象,可以很方便地测试“不隶属于任何宿主环境的通用功能”

在 React 中,通过 JSX 来描述 UI,JSX 仅仅是一个语法糖,会被 Babel 编译为 createElement 方法的调用。该方法调用之后会返回一个 JS 对象,该对象就是虚拟 DOM 对象,官方更倾向于称之为一个 React 元素。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1673608.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

object.key()用法

object.key(obj) 一、概念&#xff1a;返回一个由一个给定对象的自身可枚举属性组成的数组。 二、用法&#xff1a; 1、参数为对象&#xff1a;则返回为 对象属性名组成的数组。 let obj {日期&#xff1a;date,姓名&#xff1a;userName,地址:address}console.log(Object.k…

vue3中通过自定义指令实现loading加载效果

前言 在现代Web开发中&#xff0c;提升用户体验一直是开发者们追求的目标之一。其中&#xff0c;一个常见的场景就是在用户与应用程序进行交互时&#xff0c;特别是当进行异步操作时&#xff08;如网络请求&#xff09;&#xff0c;为用户提供即时的反馈&#xff0c;避免用户因…

Linux软件RAID:数据冗余与性能提升的完美融合

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Linux &#xff1a;从菜鸟到飞鸟的逆袭》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、软件RAID的概念 2、软件RAID与硬件RAID的对比…

中电金信:专题报告·商业银行对公数字化转型体系架构及实践拆解

当今&#xff0c;数字化转型已然成为商业银行发展的关键动力&#xff0c;在这个数字时代&#xff0c;对公业务数字化转型更是势在必行。 基于此&#xff0c;中电金信发布《商业银行对公数字化转型专题报告》&#xff08;简称《报告》&#xff09;&#xff0c;针对对公数字化转型…

揭秘四川古力未来科技抖音小店:创新优势引领电商新风潮

在当下这个数字化、网络化的时代&#xff0c;电商行业正以前所未有的速度迅猛发展&#xff0c;而抖音小店作为其中的佼佼者&#xff0c;凭借其独特的平台优势和创新的经营模式&#xff0c;吸引了越来越多的消费者和商家。其中&#xff0c;四川古力未来科技抖音小店凭借其显著的…

R语言:肿瘤突变负荷分析

> merge_maf <- function(metadata, path){ #通过合并path,还有sample sheet前两列得到每一个文件的完整路径 filenames <- file.path(path, metadata$file_id, metadata$file_name, fsep .Platform$file.sep) message (##############…

MyBatis——MyBatis查询语句

一、返回Car 当查询的结果&#xff0c;有对应的实体类&#xff0c;并且查询结果只有一条时&#xff1a; &#xff08;查询结果只有一条也可以用 List 集合接收&#xff09; package org.qiu.mybatis.mapper;import org.qiu.mybatis.pojo.Car;/*** author 秋玄* version 1.0*…

WHAT - 支持小程序的跨端框架(一)

一、背景 在 WHAT - Hybrid App 详解系列&#xff08;一&#xff09; 中我们介绍过 React Native、weex 以及 flutter 等跨平台开发技术。 随着微信小程序、百度小程序、支付宝小程序、字节跳动小程序、快应用等场景的流行&#xff0c;支持小程序或快应用的跨端诉求也促进了一…

【HarmonyOS】综合应用-《校园通》

概念 本文结合之前的笔记文章知识点&#xff0c;做一个综合性的小应用。 创建一个ArkTS语言的鸿蒙项目&#xff0c;搭建首页面 其界面代码如下&#xff0c;该界面使用了垂直布局&#xff0c;相对布局&#xff0c;轮播布局&#xff0c;以及图片&#xff0c;文本等组件的综合运…

Python API和微服务的测试库之httpretty使用详解

概要 在现代软件开发中,API和微服务的测试是确保应用稳定性和功能正确性的关键环节。Python的HTTPretty库提供了一个强大的工具,允许开发者在不实际发起网络请求的情况下模拟HTTP请求和响应。本文将全面介绍HTTPretty的安装、特性、基本与高级功能,并结合实际应用场景,展示…

Leetcode—287. 寻找重复数【中等】(快慢指针算法)

2024每日刷题&#xff08;136&#xff09; Leetcode—287. 寻找重复数 快慢指针算法思想 low fast 时&#xff0c;快慢指针相遇&#xff0c;low 走过的距离是初始点&#xff08;0&#xff09;到环状开始的点 &#xff08;x&#xff09; 加上 环状开始的点&#xff08;x&…

如何规划数据中台

1. 数据中台是一套解决方案 在数聚看来&#xff0c;数据中台是一套可持续“让企业数据用起来”的机制&#xff0c;是一套解决方案&#xff0c;不仅是一个平台。让数据更加灵活地支撑前端业务&#xff0c;通过持续沉淀企业数据复用能力形成数据从采集、治理、开发到数据服务的一…

运维安全管理系统:“四集中”管理 解决迫切问题

日前&#xff0c;国内专注于保密与非密领域的分级保护、等级保护、业务连续性安全和大数据安全产品解决方案与相关技术研究开发的领军企业——国联易安依托自身强大的研发能力&#xff0c;丰富的行业经验&#xff0c;自主研发了新一代软硬件一体化统一安全运维平台——国联易安…

leetcode.环形链表问题

目录 题目1 示例 解题思路 代码实现 补充 题目2 示例 解题思路 代码实现 题目1 该题链接&#xff1a;https://leetcode.cn/problems/linked-list-cycle/description/ 示例 解题思路 要创建两个指针一个是快指针(fast)&#xff0c;另一个慢指针(slow)。快指针走两步慢指…

JSP相关题目练习

一、前置知识 【eclipse/IDEA】如何在IDE里创建一个Java Web项目&#xff1f; 1. 实现Bean类的User实例 以一个实现Bean类User的实例。在Eclipse里调用Tomcat服务器运行。 Javabean是一种Java类&#xff0c; 通过封装属性和方法成为具有某种功能或者处理某个业务的对象&…

MyBatis-Plus核心功能详解:条件构造器、自定义SQL与Service接口

在Java的Web开发中&#xff0c;MyBatis-Plus作为MyBatis的增强工具&#xff0c;提供了许多实用的功能&#xff0c;极大地简化了数据库操作的开发过程。下面&#xff0c;我们将详细探讨MyBatis-Plus的三大核心功能&#xff1a;条件构造器、自定义SQL以及Service接口。 一、条件…

用掼蛋的智慧优化图形化编程体验

周末的午后&#xff0c;阳光透过卧龙家庭院的树叶&#xff0c;在地上洒下一片斑驳的光影。微风轻拂&#xff0c;树叶沙沙作响&#xff0c;为这个宁静的庭院增添了一丝生机。 在庭院的一角&#xff0c;有一张专门用于掼蛋的桌子。桌子周围摆放着几把舒适的椅子&#xff0c;此时&…

Human Serum Albumin ELISA kit(人血清白蛋白HSA)

人血清白蛋白&#xff08;Human Serum Albumin, HSA&#xff09;是人体血液中的血清白蛋白。它约占血清蛋白的一半&#xff0c;由肝脏产生。白蛋白具有运输荷尔蒙、脂肪酸和其他化合物、缓冲pH值和维持血管压力等功能。人血清白蛋白是一种高水溶性球状单体血浆蛋白&#xff0c;…

[AWS] stepfunctions-local

本质是本地docker,只支持异步调用 run aws-stepfunctions-localdocker run -p 8083:8083 \ --mount type=bind,readonly,source=/path/MockConfigFile.json,destination=/home/StepFunctionsLocal/MockConfigFile.json \ -e SFN_MOCK_CONFIG="/home/StepFunctionsLocal/…

ranger 队列划分和权限管控方法

创建用户 创建用户ngk【KDE首页->租户管理->集群用户->添加用户】: 创建用户组ngk_group并绑定 ngk用户【KDE首页->租户管理->集群用户->添加用户组】: 创建角色,并绑定用户组 ngk_group 【KDE首页->租户管理->集群用户->添加角色】: 创建队列…