深入理解react中的虚拟DOM、diff算法

文章结构:

  • React中的虚拟DOM是什么?
  • 虚拟DOM的简单实现(diff算法)
  • 虚拟DOM的内部工作原理
  • React中的虚拟DOM与Vue中的虚拟DOM比较

React中的虚拟DOM是什么?

    虽然React中的虚拟DOM很好用,但是这是一个无心插柳的结果。   

   React的核心思想:一个Component拯救世界,忘掉烦恼,从此不再操心界面。

1. Virtual Dom快,有两个前提

1.1 Javascript很快

   Chrome刚出来的时候,在Chrome里跑Javascript非常快,给了其它浏览器很大压力。而现在经过几轮你追我赶,各主流浏览器的Javascript执行速度都很快了。

   在 https://julialang.org/benchmarks/ 这个网站上,我们可以看到,JavaScript语言已经非常快了,和C就是几倍的关系,和java在同一个量级。所以说,单纯的JavaScript还是还是很快的。

  

1.2 Dom很慢

  当创建一个元素比如div,有以下几项内容需要实现: HTML elementElementGlobalEventHandler。简单的说,就是插入一个Dom元素的时候,这个元素上本身或者继承很多属性如 width、height、offsetHeight、style、title,另外还需要注册这个元素的诸多方法,比如onfucos、onclick等等。 这还只是一个元素,如果元素比较多的时候,还涉及到嵌套,那么元素的属性和方法等等就会很多,效率很低。

  比如,我们在一个空白网页的body中添加一个div元素,如下所示:

  这个元素会挂载默认的styles、得到这个元素的computed属性、注册相应的Event Listener、DOM Breakpoints以及大量的properties,这些属性、方法的注册肯定是需要h耗费大量时间的。

   尤其是在js操作DOM的过程中,不仅有dom本身的繁重,js的操作也需要浪费时间,我们认为js和DOM之间有一座桥,如果你频繁的在桥两边走动,显然效率是很低的,如果你的JavaScript操作DOM的方式还非常不合理,那么显然就会更糟糕了。 

  而 React的虚拟DOM就是解决这个问题的! 虽然它解决不了DOM自身的繁重,但是虚拟DOM可以对JavaScript操作DOM这一部分内容进行优化

  

  比如说,现在你的list是这样:

<ul>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>

  你希望把它变成下面这样:

<ul>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>

  

  通常的操作是什么

  先把0, 1,2,3这些Element删掉,然后加几个新的Element 6,7,8,9,10进去,这里面就有4次Element删除,5次Element添加。共计9次DOM操作

  

  那React的虚拟DOM可以怎么做呢

  而React会把这两个做一下Diff,然后发现其实不用删除0,1,2,3,而是可以直接改innerHTML,然后只需要添加一个Element(10)就行了,这样就是4次innerHTML操作加1个Element添加。共计5此操作,这样效率的提升是非常可观的。

  

2、 关于React

2.1 接口和设计

  在React的设计中,是完全不需要你来操作DOM的我们也可以认为,在React中根本就没有DOM这个概念,有的只是Component。 

  当你写好一个Component以后,Component会完全负责UI,你不需要也不应该去也不能够指挥Component怎么显示,你只能告诉它你想要显示一个香蕉还是两个梨。

  隔离DOM并不仅仅是因为DOM慢,而也是为了把界面和业务完全隔离,操作数据的只关心数据,操作界面的只关心界面。比如在websocket聊天室的创建房间时,我们可以首先Component写好,然后当获取到数据的时候,只要把数据放在redux中就好,然后Component就动把房间添加到页面中去,而不是你先拿到数据,然后使用js操作DOM把数据显示在页面上。

  即我提供一个Component,然后你只管给我数据,界面的事情完全不用你操心,我保证会把界面变成你想要的样子。所以说React的着力点就在于View层,即React专注于View层。你可以把一个React的Component想象成一个Pure Function,只要你给的数据是[1, 2, 3],我保证显示的是[1, 2, 3]。没有什么删除一个Element,添加一个Element这样的事情。NO。你要我显示什么就给我一个完整的列表。

  另外,Flux虽然说的是单向的Data Flow(redux也是),但是实际上就是单向的Observer,Store->View->Action->Store(箭头是数据流向,实现上可以理解为View监听Store,View直接trigger action,然后Store监听Action)。

  

2.2 实现

  那么react如何实现呢? 最简单的方法就是当数据变化时,我直接把原先的DOM卸载,然后把最新数据的DOM替换上去。 但是,虚拟DOM哪去了? 这样做的效率显然是极低的。

  所以虚拟DOM就来救场了。

  那么虚拟DOM和DOM之间的关系是什么呢? 

  首先,Virtual DOM并没有完全实现DOM,即虚拟DOM和真正地DOM是不一样的Virtual DOM最主要的还是保留了Element之间的层次关系和一些基本属性。因为真实DOM实在是太复杂,一个空的Element都复杂得能让你崩溃,并且几乎所有内容我根本不关心好吗所以Virtual DOM里每一个Element实际上只有几个属性,即最重要的,最为有用的,并且没有那么多乱七八糟的引用,比如一些注册的属性和函数啊,这些都是默认的,创建虚拟DOM进行diff的过程中大家都一致,是不需要进行比对的。所以哪怕是直接把Virtual DOM删了根据新传进来的数据重新创建一个新的Virtual DOM出来都非常非常非常快。(每一个component的render函数就是在做这个事情,给新的virtual dom提供input)。

   所以,引入了Virtual DOM之后,React是这么干的:你给我一个数据,我根据这个数据生成一个全新的Virtual DOM,然后跟我上一次生成的Virtual DOM去 diff,得到一个Patch,然后把这个Patch打到浏览器的DOM上去。完事。并且这里的patch显然不是完整的虚拟DOM,而是新的虚拟DOM和上一次的虚拟DOM经过diff后的差异化的部分。

  

  假设在任意时候有,VirtualDom1 == DOM1 (组织结构相同, 显然虚拟DOM和真实DOM是不可能完全相等的,这里的==是js中非完全相等)。当有新数据来的时候,我生成VirtualDom2,然后去和VirtualDom1做diff得到一个Patch(差异化的结果)。然后将这个Patch去应用到DOM1上,得到DOM2。如果一切正常,那么有VirtualDom2 == DOM2(同样是结构上的相等)

  

  这里你可以做一些小实验,去破坏VirtualDom1 == DOM1这个假设(手动在DOM里删除一些Element,这时候VirtualDom里的Element没有被删除,所以两边不一样了)。
然后给新的数据,你会发现生成的界面就不是你想要的那个界面了。

  

  最后,回到为什么Virtual Dom快这个问题上
        其实是由于每次生成virtual dom很快,diff生成patch也比较快,而在对DOM进行patch的时候,虽然DOM的变更比较慢但是React能够根据Patch的内容优化一部分DOM操作,比如之前的那个例子。

  重点就在最后,哪怕是我生成了virtual dom(需要耗费时间)哪怕是我跑了diff(还需要花时间)但是我根据patch简化了那些DOM操作省下来的时间依然很可观(这个就是时间差的问题了,即节省下来的时间 > 生成 virtual dom的时间 + diff时间)。所以总体上来说,还是比较快。

  

简单发散一下思路,如果哪一天,DOM本身的已经操作非常非常非常快了,并且我们手动对于DOM的操作都是精心设计优化过后的,那么加上了VirtualDom还会快吗
当然不行了,毕竟你多做了这么多额外的工作

但是那一天会来到吗?
        诶,大不了到时候不用Virtual DOM。

注: 此部分内容整理自:https://www.zhihu.com/question/29504639/answer/44680878

虚拟DOM的简单实现(diff算法)

目录

  • 1 前言
  • 2 对前端应用状态管理思考
  • 3 Virtual DOM 算法
  • 4 算法实现
    • 4.1 步骤一:用JS对象模拟DOM树
    • 4.2 步骤二:比较两棵虚拟DOM树的差异
    • 4.3 步骤三:把差异应用到真正的DOM树上
  • 5 结语
  • 6 References

前言

  在上面一部分中,我们已经简单介绍了虚拟DOM的答题思路和好处,这里我们将通过自己写一个虚拟DOM来加深对其的理解,有一些自己的思考。

  

对前端应用状态管理思考

  维护状态,更新视图

  

  

源码地址: https://github.com/livoras/simple-virtual-dom

参考文章:https://github.com/livoras/blog/issues/13

  

  
  

  

  

  

  

时间: 2024-10-03 04:54:29

深入理解react中的虚拟DOM、diff算法的相关文章

图解vue中 v-for 的 :key 的作用,虚拟dom Diff算法

其实不只是vue,react中在执行列表渲染时也会要求给每个组件添加上key这个属性. 要解释key的作用,不得不先介绍一下虚拟DOM的Diff算法了. 我们知道,vue和react都实现了一套虚拟DOM,使我们可以不直接操作DOM元素,只操作数据便可以重新渲染页面.而隐藏在背后的原理便是其高效的Diff算法. vue和react的虚拟DOM的Diff算法大致相同,其核心是基于两个简单的假设: 1.两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构. 2.同一层级的一组节点,他们

react虚拟dom diff算法

react虚拟dom:依据diff算法台 前端:更新状态.更新视图:所以前端页面的性能问题主要是由Dom操作引起的,解放Dom操作复杂性 刻不容缓 因为:Dom渲染慢,而JS解析编译相对非常非常非常快!jsg更容易表示节点 所以:把js和html混写在一起来解决,React出现了!!! diff算法是虚拟dom核心: 传统的diffs算法复杂度是次方级别增长,而react用的优化过的diff算法: 过程:1.节点比较(属性.文本):2.记录差别(编号):3.增删改查(js): 优化点: 情景1:

16_虚拟dom和dom diff算法

虚拟dom的作用:是为了减少操作真实的dom 初始化显示界面的过程: 1.创建虚拟dom树——>真实dom树——>绘制页面显示 更新界面的过程: 2.绘制页面显示——>setState()更新状态——>重新创建虚拟dom树——>新/旧 dom树比较差异——>更新对应差异真实 dom树——>局部页面重绘(批量更新) diff算法是用:判断哪个区域需要更新,减小更新的区域 更新对应差异真实dom树用到了diff算法 原文地址:https://www.cnblogs.c

理解JavaScript中BOM和DOM的关系

JavaScript 有三部分构成,ECMAScript,DOM和BOM,根据宿主(浏览器)的不同,具体的表现形式也不尽相同,ie和其他的浏览器风格迥异.对象是JavaScript是重要API,包含内置对象.外部对象(window对象.dom对象)和自定义对象. 1.BOM全称Browser Object Model,即浏览器对象模型,主要处理浏览器窗口和框架. 2.DOM全称Document Object Model,即文档对象模型,是 HTML 和XML 的应用程序接口(API),遵循W3C

如何理解react中的super(),super(props)

用es6的class(类)的方法创建组件: 子类继承父类的属性:需要使用super()继续父类的属性,同时创建this(子类本身没有this); 如果像上图一样需要定义props的属性 this.props.xixi="哈哈",则需要用 super(props) 如果不定义props的属性,只定义状态this.state ,就可以直接super(); 这是为什么呢? 其实很简单,因为this.props必须要是一个对象,才能在它下面定义属性 而constructor(props){}传

虚拟DOM介绍

[转自]:https://www.jianshu.com/p/616999666920 为什么需要虚拟DOM 先介绍浏览器加载一个HTML文件需要做哪些事,帮助我们理解为什么我们需要虚拟DOM.webkit引擎的处理流程,一图胜千言: 所有浏览器的引擎工作流程都差不多,如上图大致分5步:创建DOM tree –> 创建Style Rules -> 构建Render tree -> 布局Layout –> 绘制Painting 第一步,用HTML分析器,分析HTML元素,构建一颗DO

ReactiveNative学习之Diff算法

React 源码剖析系列 - 不可思议的 react diff深入浅出React(四):虚拟DOM Diff算法解析React diff 算法总结链接引用的文章React出于性能的考虑,为了避免频繁操作DOM,采用了虚拟DOM结构(virtual DOM):每当虚拟DOM树发生变化树发生变化时,React会将当前DOM树和之前的虚拟DOM树进行diff算法对比,得到虚拟DOM结构的区别,然后仅仅渲染差异部分.ReactiveNative官方称,不同类型的 component 是很少存在相似 DO

react虚拟dom与diff算法

react拥有极速渲染的特点,这个特点依靠的就是react的虚拟dom和diff算法 对比两个图就可以发现标准dom机制下,用户在应用上的操作是直接对真实dom进行操作的,在react中我们操作 的是虚拟dom,用户的操作产生的数据改变或者state变量改变,都会保存到虚拟dom上,之后再批量的对这些更 改进行diff算法计算,对比操作前后的虚拟dom树,把更改后的变化再同步到真实dom上 虚拟DOM的原理: React会在内存中维护一个虚拟DOM树,对这个树进行读或写,实际上是对虚拟DOM进行

React 虚拟dom与diff算法

一.React的虚拟dom react生成真实dom的步骤如下: 1.state(数据)与模版结合生成虚拟dom. 2.React根据虚拟dom的结构生成真实dom节点(1). 3.数据发生改变时,生成新的虚拟dom. 4.新的虚拟dom与原先的虚拟dom进行比较,将新的虚拟dom变动的部分替换原虚拟dom.(2) 5.根据变动后的虚拟dom结构生成真实的dom. 注解:(1)React根据虚拟dom生成真实dom,而不是直接生成真实dom.根据这个特性,可以实现跨端应用(React Nativ