React的虚拟DOM

上一篇文章中,DOM树的信息能够用JavaScript对象来表示,反过来,能够根据这个用JavaScript对象表示的树结构来真正构建一颗DOM树。 用JavaScript对象表示DOM信息和结构,当状态变动的时候,从新渲染这个JavaScript的对象结构,固然这样作,其实并无更新到真正的页面上。前端

可是能够用新渲染的对象树和旧的树进行对比,记录这两棵树的差别。记录下来的不一样就是咱们须要对页面真正的DOM操做,而后把它们应用在真正的DOM树上,页面才会真正变动。node

###Virtual DOM算法的实现步骤 1.用JavaScript对象结构表示DOM树的结构,而后用这个树构建一个真正的DOM树,插到文档中。react

//函数参数的定义,解构赋值中的一个用途
function Element({tagName,props,children}){
    if(!(this instanceof Element)){
        return new Element({tagName,props,children});
    }

    this.tagName = tagName;
    this.props = props || {};
    this.children = children || [];
}

2.当状态变化的时候,从新构建一颗新的对象树,而后用新的树和旧的树进行比较,记录两颗树的差别。 3.把2所记录的差别应用到步骤1所构建的真正的DOM树上,视图就更新了。 Virtual DOM实质上是在JS和DOM之间作了一个缓存,能够类比cpu和硬盘,既然硬盘这么慢,咱们就在它们之间加个缓存,既然DOM这么慢,就在它们JS和DOM之间加个缓存。CPU(JS)只操做内存(Virtual DOM),最后的时候再把变动写入硬盘(DOM)。算法

####步骤一:见前一篇博客 ####步骤二:比较两颗虚拟DOM树的差别 1.深度优先遍历,记录差别 在实际的代码中,会对新旧两颗树进行一个深度优先的遍历,这样每一个节点都会有一个惟一的标记。 缓存

在深度优先遍历的时候,每当遍历到一个节点的时候就会和新的DOM树进行比较,若是有差别,就会记录到一个对象里面。 2.这里会涉及到差别类型 (1)替换掉原来的节点,例如把上面的div换成了section (2)移动、删除、新增子节点 (3)修改节点的属性 (4)对于文本节点,文本内容可能会改变。dom

####步骤三:把差别引用到真正的DOM树上 函数

由于步骤一所构建的JavaScript对象树和render出来的真正的DOM树的信息、结构是同样的。因此咱们能够对那颗DOM树也进行深度优先遍历,遍历的时候从步骤二生成的差别对象中找出当前遍历的节点差别,而后进行DOM操做。 ####虚拟DOM算法的思想 标准的DOM机制是用户在应用上的操做实际反映的是直接对真实的dom进行操做,而在React中,用户在应用中对dom的操做其实是对虚拟dom的操做,用户的操做产生的数据改变或者state变量改变都会应用到虚拟dom上,以后再批量的对这些更改进行diff算法计算,对比操做先后的虚拟dom树,把更改后的变化再同步到真实dom上。(在虚拟dom上执行屡次修改,在真实dom中,只会执行一次dom操做,由于在React虚拟dom机制中,它会把全部的操做都合并,只会对比刚开始的状态和最后操做的状态,二者中找出不一样,而后再同步到真实dom中。)this

####react的独特的diff算法 diff算法的处理方法,对操做先后的dom树的同一层的节点进行对比,一层一层对比。,这样时间复杂度就为o(n)。 code

####比较两颗虚拟DOM树的差别对象

在用js对象表示DOM结构后,当页面状态发生变化时须要操做DOM的时候,咱们能够先经过虚拟DOM计算出新的DOM树和旧的DOM树之间的最小修改量,而后最后一次性的将差别修改到真实DOM上。 下图是一个简单的两个虚拟DOM之间的差别 可是真实的场景下的DOM结构很复杂,咱们必须借助于一个有效的DOM树比较算法。 -(1)如何比较两个DOM树

  • (2)如何记录节点之间的差别 #####如何比较两个DOM树

计算两颗树之间的差别的常规算法复杂度是O(n的3次方),一个文档的DOM结构有上百个节点是正常的状况,这种复杂度不能应用于实际项目。因此,针对前端的具体状况,咱们不多跨级别的修改DOM节点,一般是修改节点的属性、调整子节点的顺序、添加子节点等。因此咱们通常对同级别节点进行比较,避免了diff算法的复杂性。对同级节点进行比较的经常使用方法就是深度优先遍历。在深度优先遍历过程当中,每一个节点都会有一个惟一的标记。在深度优先遍历的时候,每遍历到一个节点就把该节点和新的树进行对比。若是有差别就记录到一个对象里面。

#####如何记录节点之间的差别 因为咱们对DOM采起的是同级比较,所以节点之间的差别能够归结为四种类型

  • 修改节点属性:用PROPS表示
  • 修改文本节点内容: 用TEXT表示
  • 替换原有节点,用REPLACE表示
  • 调整子节点,包括移动、删除、添加等,用RECODER表示 对于节点之间的差别,能够很方便的使用上述四种方式进行记录,好比当旧节点被替换的时候:
{type:REPLACE,node newNode}

当旧节点的属性修改时

{type:PROPS,props newProps}

每一个节点都有一个编号,若是对应的节点有变化,那么就把相应变化的类别记录下来便可。最后将这个差别对真实DOM作最小化的修改。

相关文章
相关标签/搜索