Bootstrap

虚拟DOM以及Diff算法

前言

React性能的提升很大程度上是因为不直接操作DOM,DOM是很慢的,其元素非常庞大,页面的性能问题,大部分都是由DOM操作引起的。而生成的虚拟DOM实际来说就是一个JS对象,操作JS对象所要耗费的性能远远比直接操作真实DOM产生的性能损耗要小得多。

原始渲染版本0.0

1. state数据
2. JSX模板
3. 数据+模板 结合,生成真实DOM,来显示
4. state数据发生改变
5. 数据+模板 结合,生成真实DOM,替换原始的DOM    (耗费大量性能)

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

改良1.0

1. state数据
2. JSX模板
3. 数据+模板 结合 ,生成真实DOM,挂载后进行显示
4. state数据发生改变
5. 数据+模板 结合,生成真实DOM,并不替换原始的DOM
6. 新的DOM(JS底层中的DocumentFragment文档碎片,处于内存中,并没有真实的挂载到页面)和 原始的DOM 进行对比,找差异(消耗性能)
7. 找出input框发生了变化
8. 只能新的DOM中的 input元素,替换掉老的DOM中的input元素   (节约性能)

缺陷: 性能的提升并不明显

改良2.0 虚拟DOM

1. state数据
2. JSX模板
3. 数据+模板 结合,生成虚拟DOM,(虚拟DOM就是一个JS对象,用它来描述真实DOM)(损耗性能:但此时的性能损耗非常小哦,用js生成一个js对象)      
	虚拟DOM: [ "div", { id : 'abc'},  [ "span", { }, 'hello world' ]]                    (用js生成一个DOM的性能损耗代价极高)
4. 用虚拟DOM的结构 生成真实DOM,挂载后进行显示
	真实DOM:<div id='abc'><span>hello world</span></div>
5. state发生变化
6. 数据+模板 生成新的虚拟DOM,(极大的提升了性能,不用生成真实的DOM)
   新的虚拟DOM: [ "div", { id : 'abc'},  [ "span", { }, 'bye bye!!!' ]]
7. 比较原始虚拟DOM 和新的虚拟DOM的区别,找到区别是span中的内容   (性能提升:两个js对象对比非常不消耗性能)
8. 直接操作DOM,改变span中的内容

虚拟DOM提高性能的根本原因: 减少了对真实DOM的创建,以及对比,取而代之通过对比虚拟DOM,即js对象,比较js对象不怎么消耗性能,创建以及比较真实的DOM及其消耗性能,因此使得React的底层实现了极大的性能飞跃。

深入虚拟DOM

<div>content</div> 即为一个JSX模板

在render进行渲染的时候,JSX模板的内容其实最终会转化成React.createElement…去创建元素。
React.createElement('div',{},'content'),然后生成虚拟DOM,再根据虚拟DOM的结构生成真实DOM,挂载后进行显示。
整体流程:JSX -->creatElement --> 虚拟DOM(js对象)–> 真实DOM

// return <div>content</div>        JSX模板
return React.createElement('div',{},'content')

优点:1. 性能提升了 2. 它使得跨端应用得以实现。React Native

虚拟DOM 中的Diff算法(diff–>different):

比对原始虚拟DOM和新生成的虚拟DOM

Diff算法: 当state数据发生改变的时候,右侧会生成一个新的虚拟DOM。接下来两个DOM做比对,找到差异后更新真实的DOM。方法:同层比对,先对比顶层的虚拟DOM节点,如果不同,则直接删除原始DOM上该节点以及下面的所有节点;
同层比较

Key值: 虚拟DOM的比对会根据key值做关联,提高性能。a-a进行比对,b-b进行比对,只有z不同,只需要添加z节点;利用key值提升性能的前提是:原始虚拟DOM上的key值a,b,c,d,e 在新生成的虚拟DOM树上,仍然是a,b,c,d,e;
联系到我们日常编程中,之所以不建议使用index作为key值,是因为key值的不稳定性,例如原始虚拟DOM 节点的key值分别对应:a 0 b 1 c 2,删除a节点,更新后的对应key值变为:b 0 c 1,从而失去了key值存在的意义;我们可以用item当做key值,a-a b-b c-c --> b-b c-c ,原始和新生成的key保持一致,依然能够保持正确的对应关系,从而可以快速进行比对。
key值
同层比对和key值比对都是Diff算法中的一部分;
React的功能提升不仅限于Diff算法,下面是如何利用setState进行性能的提升,以及为什么要将其设置成异步函数。

setState性能优化:
setState设计为异步的初衷是为了提升底层的性能;进行一次setState的时候,state数据改变,生成新的虚拟DOM,然后开始比对,然后更新DOM如果setState连续出现三次,且时间间隔十分短暂,React可以把三次setState合并为一次setState,只需做一次虚拟DOM比对,然后去更新一次DOM,如此则可省去额外的两次DOM比对,带来的性能浪费,提高性能;

简单来说:如果每次调用 setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样效率是很低的;最好的办法应该是获取到多个更新,之后进行批量更新;
setState算法
React中还有很多提升性能的方法:虚拟DOM 中的Diff算法,异步setState,shouldComponentUpdate( )等都可以提高性能。

;