react用虚拟dom有什么好处
推荐于2018-04-03 · 知道合伙人互联网行家
React 主要的目标是提供一套不同的, 高效的方案来更新 DOM.不是通过直接把 DOM 变成可变的数据, 而是通过构建 “Virtual DOM”, 虚拟的 DOM, 随后 React 处理真实的 DOM 上的更新来进行模拟相应的更新。
引入额外的一个层怎么就更快了呢?
那不是意味着浏览器的 DOM 操作不是最优的, 如果在上边加上一层能让整体变快的话?是有这个意思, 只不过 virtual DOM 在语义上和真实的 DOM 有所差别.最主要的是, virtual DOM 的操作, 不保证马上就会产生真实的效果.这样就使得 React 能够等到事件循环的结尾, 而在之前完全不用操作真实的 DOM。在这基础上, React 计算出几乎最小的 diff, 以最小的步骤将 diff 作用到真实的 DOM 上。批量处理 DOM 操作和作用最少的 diff 是应用自身都能做到的.任何应用做了这个, 都能变得跟 React 一样地高效。但人工处理出来非常繁琐, 而且容易出错. React 可以替你做到。
前面提到 virtual DOM 和真实的 DOM 有着不用的语义, 但同时也有明显不同的 API。
DOM 树上的节点被称为元素, 而 virtual DOM 是完全不同的抽象, 叫做 components。
component 的使用在 React 里极为重要, 因为 components 的存在让计算 DOM diff 更高效。
简单的说就是:
当然如果真的这样大面积的操作 DOM,性能会是一个很大的问题,所以 React 实现了一个虚拟 DOM,组件 DOM 结构就是映射到这个虚拟 DOM 上,React 在这个虚拟 DOM 上实现了一个 diff 算法,当要更新组件的时候,会通过 diff 寻找到要变更的 DOM 节点,再把这个修改更新到浏览器实际的 DOM 节点上,所以实际上不是真的渲染整个 DOM 树。这个虚拟 DOM 是一个纯粹的 JS 数据结构,所以性能会比原生 DOM 快很多。
什么是虚拟DOM(Virtual DOM)
首先,解释下虚拟DOM。虚拟DOM保存了真实DOM的层次关系和一些基本属性,与真实DOM一一对应。虚拟DOM的工作原理是:数据 -> 全新的虚拟DOM -> 与上一个状态的虚拟DOM进行diff算法比较,得到一个Patch -> 把这个Patch打到浏览器的DOM上。所以虚拟DOM叫的挺高端,其实就有点类似DocumentFragment,把多次DOM操作做一个批处理。于是,有一件很有意思的事情,如果你手动在DOM里删除一些节点,使得虚拟DOM与真实DOM不能一一对应了,再改变state重新render页面,页面就乱了。
diff算法
其次,想分享下diff算法。前两天看司徒正美推销他的Avalon,也分析了下React,说了一句话,现在前端框架比的是算法。diff算法说白了就是比较两个文件不同的算法。一般diff算法的复杂度是O(n3)。Facebook工程师根据前端页面特点做了两个假设(如果你好奇是什么假设这么神奇,可以来问我),把比较前后两个状态虚拟DOM的diff算法的复杂度降到了O(n)。这个diff算法分为三部分,我用三句话总结:
1. 虚拟DOM树同一位置不同类型(标签不同)的节点:删除前一状态节点,插入后一状态节点,哪怕节点有子节点也这样做;
2. 虚拟DOM树同一位置相同类型但个别属性不同的节点,对前一状态节点进行属性重设;
3. 列表节点(就是我们用循环创建的类似Array的节点),如果没有unique key(没有控制台会报警告的)就按照前面两种方式解决,如果有unique key就找到key相应的位置插入节点。
真的很简单,印证了一句话,简单的算法往往效率最高,好像我做推荐算法,单个算法不混合的话,依然是协同过滤效果最好。
虚拟DOM快在哪里
然后,js计算肯定要比DOM操作快啊,每次DOM操作都很有可能引起回流(Reflow)和重绘(Repaint)啊。当然浏览器也不傻,不是你每次操作DOM浏览器都重绘一次,一般浏览器会按照时间或次数间隔进行DOM操作的批处理。那问题来了,到底是浏览器优化后的DOM批处理快,还是React的虚拟DOM+优化diff算法快。这个我没有测试过,根据博客上内容,React的优化更人性化、也更快。速度快肯定是虚拟DOM的一个优点,另外一点,浏览器对DOM操作批处理的主动权不在前端人员手中,React将这种批处理的时机选择交到了我们手中,看我们什么时候想render页面。这个和AJAX+回调带来的问题一样,当我们发送一个AJAX,然后指定一个回调函数时候,对回调里代码的控制权就交给浏览器了,所以前端人员常常感觉AJAX不可控,不知道回调什么时候执行完了,页面一大堆flag。
React 主要的目标是提供一套不同的, 高效的方案来更新 DOM.不是通过直接把 DOM 变成可变的数据, 而是通过构建 “Virtual DOM”, 虚拟的 DOM, 随后 React 处理真实的 DOM 上的更新来进行模拟相应的更新。
引入额外的一个层怎么就更快了呢?
那不是意味着浏览器的 DOM 操作不是最优的, 如果在上边加上一层能让整体变快的话?是有这个意思, 只不过 virtual DOM 在语义上和真实的 DOM 有所差别.最主要的是, virtual DOM 的操作, 不保证马上就会产生真实的效果.这样就使得 React 能够等到事件循环的结尾, 而在之前完全不用操作真实的 DOM。在这基础上, React 计算出几乎最小的 diff, 以最小的步骤将 diff 作用到真实的 DOM 上。批量处理 DOM 操作和作用最少的 diff 是应用自身都能做到的.任何应用做了这个, 都能变得跟 React 一样地高效。但人工处理出来非常繁琐, 而且容易出错. React 可以替你做到。
前面提到 virtual DOM 和真实的 DOM 有着不用的语义, 但同时也有明显不同的 API。
DOM 树上的节点被称为元素, 而 virtual DOM 是完全不同的抽象, 叫做 components。
component 的使用在 React 里极为重要, 因为 components 的存在让计算 DOM diff 更高效。
简单的说就是:
当然如果真的这样大面积的操作 DOM,性能会是一个很大的问题,所以 React 实现了一个虚拟 DOM,组件 DOM 结构就是映射到这个虚拟 DOM 上,React 在这个虚拟 DOM 上实现了一个 diff 算法,当要更新组件的时候,会通过 diff 寻找到要变更的 DOM 节点,再把这个修改更新到浏览器实际的 DOM 节点上,所以实际上不是真的渲染整个 DOM 树。这个虚拟 DOM 是一个纯粹的 JS 数据结构,所以性能会比原生 DOM 快很多。