第一章理念篇——1.3 虚拟 DOM的实现

321 阅读3分钟

本专栏致力于每周分享一个项目,如果本文对你有帮助的话,欢迎点赞或者关注☘️

React18 源码系列会随着学习 React 源码的实时进度而实时更新:约,两天一小改,五天一大改。

真实 Dom

MDN官方文档介绍:DOM(Document Object Model)是Web文档(一般指XML或HTML文档)的编程接口,DOM以节点和对象的方式来表示文档,能够方便程序对文档结构、样式、内容作出改变和交互。这种编程规范是和具体编程语言无关,可以通过很多语言来实现。在浏览器环境下,我们可以通过JavaScript来调用Dom编程接口完成和页面文档的交互。

真实 Dom 对象的属性数量非常多,如果我们通过直接操作DOM来进行页面的变化,而页面A到页面B的过程中,我们需要遍历整颗 DOM 树,进行变化前后的对比,才能知道如何更新页面节点, 因此操作Dom的性能成本很高。

虚拟 DOM

由于操作 真实 DOM 对象的性能成本很高,因此引入了虚拟DOM。虚拟 DOM 就是用于描述 部分真实DOM对象属性的对象。由于真实 DOM 对象中的大部份属性在JavaScript程序中都是非必须的,因此虚拟 DOM对象 只包括 JavaScript 程序中极少部分所需要的属性。

由于虚拟 DOM 是 真实 DOM 对象的进一步抽象,代表了该DOM对象的关键信息,操作和遍历的成本很低,我们通过低成本的虚拟 DOM 来计算需要更新哪些 真实DOM对象,最后再根据计算的结果来操作和更新真实的DOM对象,即做到低性能成本也能极快的更新一个复杂页面。

JSX

JSX是由 Facebook(现 Meta Platforms, Inc.)为 React 框架引入的一种 JavaScript 的语法扩展,并不是由标准的 JavaScript 语言规范提供。所谓语法扩展,就意味着 JavaScript 语法本身是不支持 JSX 的。JSX 实际上是一个特殊的字符串格式,它看起来像 HTML,但实际上会被 babel 样的转译器转换成合法的 JavaScript。转换后的代码通常会调用 React.createElement() 来创建 React 元素,从整体来看会依次创建Fiber节点并连接在一起构建Fiber树,即workInProgress Fiber树。

当我们使用 React.createElement 来编写 React 代码的前提条件下,我们可以不用引入 babel 再来进行转义。但是 React.createElement 编写起来过于繁琐,且可读性和可维护性都相对较差,所以在实际开发中,我们一般会使用 JSX 来简化我们的编码方式。

React 认为渲染逻辑本质上与其他UI逻辑存在内在耦合。他们之间是密不可分,所以 React 没有将界面和逻辑代码分离开来,而是通过组件(Component)将他们组合在了一起。所以为了方便在 JS 中编写类似于 html 的语法,也就是 html in js, React 提供了 JSX 语法。

当你在 React 组件中写入 JSX 代码时,例如:

jsx
深色版本
const element = (
  <div className="container">
    <h1>Hello World!</h1>
  </div>
);

这段代码实际上会被 Babel 转换成类似于以下的 JavaScript 代码:

javascript
深色版本
const element = React.createElement(
  "div",
  { className: "container" },
  React.createElement("h1", null, "Hello World!")
);

这里 React.createElement() 创建了一个虚拟 Dom 对象,该对象包含标签名(类型)、属性对象、子节点。 React 通过维护这些虚拟 DOM 对象来模拟 真实的 DOM结构,每次更新的时候会通过高效的 diff 算法来确定最小的更新路径,再去更新真实 Dom对象,从而减少真实 DOM 的操作次数,提高性能。

参考链接

关于作者

作者:Wandra

内容:算法 | 趋势 |源码|Vue | React | CSS | Typescript | Webpack | Vite | GithubAction | GraphQL | Uniqpp。

专栏:欢迎关注呀🌹

本专栏致力于每周分享一个项目,如果本文对你有帮助的话,欢迎点赞或者关注☘️