写点什么

你不知道的 virtual DOM(一):Virtual Dom 介绍

  • 2020-03-08
  • 本文字数:2393 字

    阅读完需:约 8 分钟

你不知道的virtual DOM(一):Virtual Dom介绍

一、前言

目前最流行的两大前端框架,React 和 Vue,都不约而同的借助 Virtual DOM 技术提高页面的渲染效率。那么,什么是 Virtual DOM?它是通过什么方式去提升页面渲染效率的呢?本系列文章会详细讲解 Virtual DOM 的创建过程,并实现一个简单的 Diff 算法来更新页面。本文的内容脱离于任何的前端框架,只讲最纯粹的 Virtual DOM。敲单词太累了,下文 Virtual DOM 一律用 VD 表示。


这是 VD 系列文章的开篇,后续还会有更多的文章带你深入了解 VD 的奥秘。

二、VD 是什么

本质上来说,VD 只是一个简单的 JS 对象,并且最少包含 tagpropschildren三个属性。不同的框架对这三个属性的命名会有点差别,但表达的意思是一致的。它们分别是标签名(tag)、属性(props)和子元素对象(children)。下面是一个典型的 VD 对象例子:


{  tag: "div",  props: {},  children: [    "Hello World",     {      tag: "ul",      props: {},      children: [{        tag: "li",        props: {          id: 1,          class: "li-1"        },        children: ["第", 1]      }]    }  ]}
复制代码


VD 跟 dom 对象有一一对应的关系,上面的 VD 是由以下的 HTML 生成的:


<div>  Hello World  <ul>    <li id="1" class="li-1">      第1    </li>  </ul></div>
复制代码


一个 dom 对象,比如 li,由 tag(li), props({id:1,class:"li-1"})children(["第",1])三个属性来描述。

三、为什么需要 VD

借助 VD,可以达到有效减少页面渲染次数的目的,从而提高渲染效率。我们先来看下页面的更新一般会经过几个阶段:



从上面的例子中,可以看出页面的呈现会分以下 3 个阶段:


  • JS 计算

  • 生成渲染树

  • 绘制页面


这个例子里面,JS 计算用了 691毫秒,生成渲染树 578毫秒,绘制 73毫秒。如果能有效的减少生成渲染树和绘制所花的时间,更新页面的效率也会随之提高。


通过 VD 的比较,我们可以将多个操作合并成一个批量的操作,从而减少 dom 重排的次数,进而缩短了生成渲染树和绘制所花的时间。至于如何基于 VD 更有效率的更新 dom,是一个很有趣的话题,日后有机会将另写一篇文章介绍。

四、如何实现 VD 与真实 DOM 的映射

我们先从如何生成 VD 说起。借助 JSX 编译器,可以将文件中的 HTML 转化成函数的形式,然后再利用这个函数生成 VD。看下面这个例子:


function render() {  return (    <div>      Hello World      <ul>        <li id="1" class="li-1">          第1        </li>      </ul>    </div>  );}
复制代码


这个函数经过 JSX 编译后,会输出下面的内容:


function render() {  return h(    'div',    null,    'Hello World',    h(      'ul',      null,      h(        'li',        { id: '1', 'class': 'li-1' },        '\u7B2C1'      )    )  );}
复制代码


这里的 h 是一个函数,可以起任意的名字。这个名字通过 babel 进行配置:


// .babelrc文件{ "plugins": [  ["transform-react-jsx", {   "pragma": "h"  // 这里可配置任意的名称  }] ]}
复制代码


接下来,我们只需要定义 h 函数,就能构造出 VD:


function flatten(arr) {  return [].concat.apply([], arr);}
function h(tag, props, ...children) { return { tag, props: props || {}, children: flatten(children) || [] };}
复制代码


h 函数会传入三个或以上的参数,前两个参数一个是标签名,一个是属性对象,从第三个参数开始的其它参数都是 children。children 元素有可能是数组的形式,需要将数组解构一层。比如:


function render() {  return (    <ul>      <li>0</li>      {        [1, 2, 3].map( i => (          <li>{i}</li>        ))      }    </ul>  );}
// JSX编译后function render() { return h( 'ul', null, h( 'li', null, '0' ), /* * 需要将下面这个数组解构出来再放到children数组中 */ [1, 2, 3].map(i => h( 'li', null, i )) );}
复制代码


继续之前的例子。执行 h 函数后,最终会得到如下的 VD 对象:


{  tag: "div",  props: {},  children: [    "Hello World",     {      tag: "ul",      props: {},      children: [{        tag: "li",        props: {          id: 1,          class: "li-1"        },        children: ["第", 1]      }]    }  ]}
复制代码


下一步,通过遍历 VD 对象,生成真实的 dom


// 创建dom元素function createElement(vdom) {  // 如果vdom是字符串或者数字类型,则创建文本节点,比如“Hello World”  if (typeof vdom === 'string' || typeof vdom === 'number') {    return doc.createTextNode(vdom);  }
const {tag, props, children} = vdom;
// 1. 创建元素 const element = doc.createElement(tag);
// 2. 属性赋值 setProps(element, props);
// 3. 创建子元素 // appendChild在执行的时候,会检查当前的this是不是dom对象,因此要bind一下 children.map(createElement) .forEach(element.appendChild.bind(element));
return element;}
// 属性赋值function setProps(element, props) { for (let key in props) { element.setAttribute(key, props[key]); }}
复制代码


createElement函数执行完后,dom 元素就创建完并展示到页面上了(页面比较丑,不要介意…)。


五、总结

本文介绍了 VD 的基本概念,并讲解了如何利用 JSX 编译 HTML 标签,然后生成 VD,进而创建真实 dom 的过程。下一篇文章将会实现一个简单的 VD Diff 算法,找出 2 个 VD 的差异并将更新的元素映射到 dom 中去。


PS: 想看完整代码见这里:


代码(https://gist.github.com/dickenslian/86c4e266ae5f2134373376133bec9e3d)

参考链接:


2020-03-08 19:242038

评论 2 条评论

发布
用户头像
这里不应该是 setProps 吧,应该是 setAttributes
2020-07-29 12:45
回复
哎,没看全,不好意思,忽视。这个方法命名好有歧义 setProps 的内部实现是 setAttributes 😂
2020-07-29 13:06
回复
没有更多了
  • Excel 做数据分析?是真的很强!

    原文链接:怎样用 Excel 做数据分析?

    2022-10-28

  • Vue 模板是怎样编译的

    这一章我们开始讲模板解析编译:总结来说就是通过compile函数把tamplate解析成render Function形式的字符串compiler/index.js

    2022-11-10

  • 从源码角度看 React-Hydrate 原理

    React 渲染过程,即ReactDOM.render执行过程分为两个大的阶段:render 阶段以及 commit 阶段。React.hydrate渲染过程和ReactDOM.render差不多,两者之间最大的区别就是,ReactDOM.hydrate 在 render 阶段,会尝试复用(hydrate)浏览器现有的 dom 节点,并相互

    2022-11-14

  • 从源码角度看 React-Hydrate 原理

    React 渲染过程,即ReactDOM.render执行过程分为两个大的阶段:render 阶段以及 commit 阶段。React.hydrate渲染过程和ReactDOM.render差不多,两者之间最大的区别就是,ReactDOM.hydrate 在 render 阶段,会尝试复用(hydrate)浏览器现有的 dom 节点,并相互

    2022-10-17

  • 从源码角度看 React-Hydrate 原理

    React 渲染过程,即ReactDOM.render执行过程分为两个大的阶段:render 阶段以及 commit 阶段。React.hydrate渲染过程和ReactDOM.render差不多,两者之间最大的区别就是,ReactDOM.hydrate 在 render 阶段,会尝试复用(hydrate)浏览器现有的 dom 节点,并相互

    2022-11-02

  • 从源码角度看 React-Hydrate 原理

    React 渲染过程,即ReactDOM.render执行过程分为两个大的阶段:render 阶段以及 commit 阶段。React.hydrate渲染过程和ReactDOM.render差不多,两者之间最大的区别就是,ReactDOM.hydrate 在 render 阶段,会尝试复用(hydrate)浏览器现有的 dom 节点,并相互

    2023-03-01

  • 从源码角度看 React-Hydrate 原理

    React 渲染过程,即ReactDOM.render执行过程分为两个大的阶段:render 阶段以及 commit 阶段。React.hydrate渲染过程和ReactDOM.render差不多,两者之间最大的区别就是,ReactDOM.hydrate 在 render 阶段,会尝试复用(hydrate)浏览器现有的 dom 节点,并相互

    2022-11-25

  • 从源码角度看 React-Hydrate 原理

    React 渲染过程,即ReactDOM.render执行过程分为两个大的阶段:render 阶段以及 commit 阶段。React.hydrate渲染过程和ReactDOM.render差不多,两者之间最大的区别就是,ReactDOM.hydrate 在 render 阶段,会尝试复用(hydrate)浏览器现有的 dom 节点,并相互

    2023-02-14

  • Vue 中的 diff 算法深度解析

    模板tamplate经过parse,optimize,generate等一些列操作之后,把AST转为render function code进而生成虚拟VNode,模板编译阶段基本已经完成了,那么这一章,我们来探讨一下Vue中的一个算法策略--dom diff 首先来介绍下什么叫dom diff

    2022-11-08

  • 39|语法扩展:通过 JSX 来做语法扩展

    这节课我们就来看看JSX是如何用在Web UI开发中的。即使你不使用React,这样的模版模式也有很大的借鉴意义。

    2022-12-17

  • 架构实战营 - 模块四作业

    千万级学生管理系统的考试试卷存储方案

    2023-03-05

  • 32|Fabric:新渲染器的演进之路

    对核心渲染流程的持续迭代和优化,是 React Native 能够广受欢迎的重要原因之一。

    2023-01-01

  • 加餐|基础篇思考题答疑

    基础篇答疑来了

    2022-12-07

  • 30|JavaScript 引擎:双向通讯底层原理是什么?

    双向通讯底层原理是什么?

    2022-11-01

  • 从源码角度看 React-Hydrate 原理

    React 渲染过程,即ReactDOM.render执行过程分为两个大的阶段:render 阶段以及 commit 阶段。React.hydrate渲染过程和ReactDOM.render差不多,两者之间最大的区别就是,ReactDOM.hydrate 在 render 阶段,会尝试复用(hydrate)浏览器现有的 dom 节点,并相互

    2023-01-05

  • 16|单页面应用:如何理解和实现单页面应用开发?

    希望你充分明白单页面路由的技术原理,理解API背后是如何运行的,而不只是停留在vue-router的API使用。

    2022-12-30

  • React 源码分析 2- 深入理解 fiber

    react16 版本之后引入了 fiber,整个架构层面的 调度、协调、diff 算法以及渲染等都与 fiber 密切相关。所以为了更好地讲解后面的内容,需要对 fiber 有个比较清晰的认知。本章将介绍以下内容:

    2023-02-20

  • 深入 React 源码揭开渲染更新流程的面纱

    转前端一年半了,平时接触最多的框架就是React。在熟悉了其用法之后,避免不了想深入了解其实现原理,网上相关源码分析的文章挺多的,但是总感觉不如自己阅读理解来得深刻。于是话了几个周末去了解了一下常用的流程。也是通过这篇文章将自己的个人理解分享出

    2022-11-10

  • React 源码分析 2- 深入理解 fiber

    react16 版本之后引入了 fiber,整个架构层面的 调度、协调、diff 算法以及渲染等都与 fiber 密切相关。所以为了更好地讲解后面的内容,需要对 fiber 有个比较清晰的认知。本章将介绍以下内容:

    2022-12-08

  • 15|不可变数据:为什么对 React 这么重要?

    我们这节课的主要内容是不可变数据。

    2022-10-04

发现更多内容

喜报|3DCAT成为国内首批适配Vision Pro内容开发者

3DCAT实时渲染

实时云渲染

Java 枚举(Enums)解析:提高代码可读性与易维护性

小万哥

Java 程序人生 编程语言 软件工程 后端开发

马斯克和OpenAI:分手,不要体面

脑极体

AI

Amazon Bedrock 上的新一代 Anthropic 模型 Claude 3

亚马逊云科技 (Amazon Web Services)

生成式人工智能

AI加速“应用现代化”,金融核心系统转型正当时

华为云开发者联盟

云计算 华为云 华为云开发者联盟 华为云CodeArts 华为云盘古大模型

用几张图实战讲解MySQL主从复制

华为云开发者联盟

后端 开发 华为云 华为云开发者联盟

让运维无忧,实战解析巡检报告功能实现方案

袋鼠云数栈

大数据 运维 大数据运维 巡检报告

上云还是下云,最大挑战是什么?对话章文嵩、毕玄、王小瑞

AutoMQ

阿里云 云原生 上云 云上架构

浅谈漏洞扫描技术

于顾而言

网络安全 云安全 漏洞扫描 漏洞检测 web漏洞

小程序管理平台,企业研发效能提升利器

FinFish

小程序管理平台 小程序管理 小程序开发平台

《操作系统导论》PDF

程序员李木子

更无缝地管理 API 访问

Gingxing

kong API网关 Kong 网关 消息网关 Kong Gateway

怎样降低LED显示屏模组的成本

Dylan

科技 LED显示屏 户外LED显示屏 led显示屏厂家 户内led显示屏

活动报名|AutoMQ x 阿里云云原生创新论坛(2024.03.09)见证“新一代云原生 Kafka ”重磅发布!

AutoMQ

kafka 阿里云 云原生 论坛

Starknet 最好的钱包是什么?

BlockChain先知

Anthropic Claude 3 Sonnet 基础模型现已登陆 Amazon Bedrock

亚马逊云科技 (Amazon Web Services)

生成式人工智能

【案例分析】一个小型数据管理系统

贺公子之数据科学与艺术

StarkNet新手入门教程:教你用bitget 钱包入门

股市老人

技术管理者如何避免被裁掉(2)

芃篙君

管理

aigo发布“国民好物合创工程” 携京东、HICOOL助力中小微企业走向科技发展之路

ToB行业头条

QCN9274/WiFi 7: Exploring the cornerstone of the next generation of digital life

wallysSK

Apps分类:深度解析多维度标准与应用领域

天津汇柏科技有限公司

创业 软件开发 小程序开发 app定制开发 软件开发定制

【论文速读】 | AI驱动修复:漏洞自动化修复的未来

云起无垠

StarkNet新手入门教程:教你用bitget 钱包入门

石头财经

你不知道的virtual DOM(一):Virtual Dom介绍_文化 & 方法_大白_InfoQ精选文章