react 中的虚拟 DOM 以及 DOM diff 算法

一、react 中的虚拟 DOM

  1. 第一种方案:
  • 第一步,state 数据
  • 第二步,JSX 模版
  • 第三步,数据 + 模版的结合,生成真实的 DOM,来显示
  • 第四步,state 发生改变
  • 第五步,数据 + 模版的结合,生成真实的 DOM,替换原始的 DOM

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

  1. 第二种方案:
  • 第一步,state 数据
  • 第二步,JSX 模版
  • 第三步,数据 + 模版的结合,生成真实的 DOM,来显示
  • 第四步,state 发生改变
  • 第五步,数据 + 模版的结合,生成真实的 DOM,并不直接替换原始的DOM
  • 第六步,新的 DOM(DoucumentFragment) 和原始的 DOM 做对比,找差异
  • 第七步,找出 span 发生了变化
  • 第八步,只用新的DOM 中的span元素,替换掉老的 DOM 中的span 元素

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

  1. 第三种方案:
  • 第一步,state 数据
  • 第二步,JSX 模版
  • 第三步,数据 + 模版的结合,生成虚拟 DOM,虚拟 DOM 就是一个JS对象,用它来描述真实 DOM,耗损了性能 ['div', {id: 'abc'}, ['span', {}, 'hello word'] ]
  • 第四步,用虚拟DOM 的结构生成真实的 DOM,来显示 <div id="abc"><span>hello word</span></div>
  • 第五步, state 发生变化
  • 第六步,数据 + 模版生成新的虚拟 DOM,极大的提升了性能 ['div', {id: 'abc'}, ['span', {}, 'hello react'] ]
  • 第七步,比较原始虚拟DOM和新的虚拟DOM的区别,找打区别是 span 中的内容,极大的提升了性能
  • 第八步,直接操作DOM, 改变 span中的内容

优点:性能的提升很明显,它使得跨端应用得以实现,React Native

  1. 一个虚拟DOM元素是一个一般的JS对象,准确的说是一个对象树,倒立的,虚拟DOM保存了真实DOM的层次关系和一些基本属性,与真实DOM一一对应,如果只是更新虚拟DOM,页面是不会重绘的。

  2. 对真实 DOM进行比较耗性能,而对 JS 对象进行耗性能较小。虚拟DOM对于react的好处是减少了对真实 DOM的创建和真实 DOM 的对比,反而创建的都是JS 对象,对比的也是JS 对象,react 的底层性能也得到了很大的提升。

二、DOM diff算法

  1. setState 底层可以将多次 setState 结合成一次 setState,减少虚拟DOM的比对次数,如下图所示:
    react 中的虚拟 DOM 以及 DOM diff 算法

  2. react 的虚拟DOM比对是同层比对,逐层比对,如果一层不满足匹配的要求时,下面的就不会再 比对了,直接废弃掉,用新的替换掉老的,提升性能,如下图所示:
    react 中的虚拟 DOM 以及 DOM diff 算法

  3. react 中引入 key 值,提高比较虚拟DOM的性能,key值要稳定,能不用index 就不用 index,因为indexkey值是不稳定的,如下图所示:
    react 中的虚拟 DOM 以及 DOM diff 算法

  4. Virtual DOM 算法的基本步骤
    JS对象树表示DOM树的结构;然后用这个树构建一个真正的DOM树插到文档当中。当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异,把差异应用到真实DOM树上,视图就更新了。同层比对和 key 值都是 diff 算法的一部分。

  5. Virtual DOM 本质上就是在 JSDOM 之间做了一个缓存。可以类比 CPU 和硬盘,既然硬盘这么慢,我们就在它们之间加个缓存:既然 DOM这么慢,我们就在它们 JSDOM 之间加个缓存。CPUJS)只操作内存(Virtual DOM),最后的时候再把变更写入硬盘(DOM)。