React Diff 算法

React介绍

React是Facebook开发的一款JS库,用于构建用户界面的类库。node

它采用声明式范例,能够传递声明代码,最大限度地减小与DOM的交互。react

特色:算法

  1. 声明式设计:React采用声明范式,你能够轻松描述你的应用浏览器

  2. 高效:React经过对DOM的模拟表现,最大限度地较少与DOM的交互。性能优化

  3. 灵活:React能够与你所知道的库或框架很好地工做。app

在Web开发中,咱们总须要将变化的数据实时反应到UI上,这时就须要对DOM进行操做。而复杂或频繁的DOM操做一般是性能瓶颈产生的缘由框架


React为此引入了虚拟DOM(Virtual DOM)的机制:性能

在浏览器端用Javascript实现了一套DOM API。基于React进行开发时全部的DOM构造都是经过虚拟DOM进行,每当数据变化时,React都会从新构建整个虚拟DOM树,而后React将当前整个虚拟DOM树和上一次的虚拟DOM树进行对比,获得虚拟DOM结构的区别,而后仅仅将须要变化的部分进行实际的浏览器DOM更新。优化

React Diff 算法

虚拟DOM做为React的一大核心技术,了解其实现原理对于灵活应用有着很大帮助。spa

Javascript 虚拟DOM对象

在咱们项目中申明一个组件是这样的:

react.createElement('div', null, [
    // 建立一个img
    react.createElement('img', { src: "avatar.png", class: "profile" }),
    // 或者
    react.createElement('h1', null, [[user.firstName, user.lastName].join(' ')])
]);

最后,React都会转换成相似这样的基本对象:

{
    tagName: 'div',
    // 节点包含的属性
    properties: {
        style: {
            color: '#fff'
        }
    },
    // 子节点
    children: [],
    // 节点的惟一标识
    key: 1
}

Javascript DOM节点树

而后,React把Javascript DOM模对象 转换成 Javascript DOM节点树:

function create(vds, parent) {
  !Array.isArray(vds) && (vds = [vds]);
  // 若是没有父元素则建立个fragment来当父元素
  parent = parent || document.createDocumentFragment();
  var node;
  vds.forEach(function (vd) {
    // 若是是文字节点
    if (isText(vd)) {
      // 建立文字节点
      node = document.createTextNode(vd.text);
    } else {
      // 建立元素
      node = document.createElement(vd.tag);
    }
    // 将元素塞入父容器
    parent.appendChild(node);
    // 看看有没有子VNode,有孩子则处理孩子VNode
    vd.children && vd.children.length &&
      create(vd.children, node);
    // 看看有没有属性,有则处理属性
    vd.properties &&
      setProps({ style: {} }, vd.properties, node);
  });
  return parent;
}

Diff

如今咱们获得的是Javascript 实现的虚拟DOM树,在一个事件循环中,当state或者preps变化时,React会建立一个新的虚拟DOM树,最后进行差别渲染。

diff(previous:VTree, current:VTree) -> PatchObject

React分三种情景:


1. 分层对比


React 仅仅是尝试把树按照层级分解. 这完全简化了复杂度, 并且也不会失去不少, 由于 Web 应用不多有 component 移动到树的另外一个层级去。它们大部分只是在相邻的子节点之间移动。

2. 基于key匹配



Keys是一个VNode的惟一识别,用于对两个不一样的VTree中的VNode作匹配的。经过key锁定某个组件后,React就能够直接对比这两个差别DOM节点树,复杂度为O(n)。


因此这里有个性能优化的技巧。假设你有一个key组件,他的key属性为foo,后续又将它改成bar,那么React就会掉过DOM diff,同时彻底弃置div全部自元素,从头渲染。在渲染大型子树以免diff计算时,这样的设计颇有用,由于咱们知道这种计算就是在浪费时间。

3. 基于自定义元素作优化



React提供自定义元素,因此匹配很简单。React 只会匹配相同 class 的 component。


好比, 若是有个<Header><ExampleBlock>替换掉了,
React 会删除掉 header 再建立一个example block。咱们不须要化宝贵的时间去匹配两个不大可能有类似之处的 component。

结束

React在你调用 component 的 setState 方法的时候, 将其标记为 dirty,到每个事件循环结束, React 检查全部标记 dirty 的 component 从新绘制。每次调用 setState 会从新计算整个子树.若是你想要提升性能, 尽可能少调用 setState。


最后, 你还有可能去掉一些子树的从新渲染,若是你在 component 上实现function shouldComponentUpdate(nextProps, nextState) 的话,你根据 component 的前一个和下一个 props/state,告诉 React 这个 component 没有更新, 也不须要从新绘制。

原创文章,欢迎转载。转载请注明:转载自Fs21 ' s Home,谢谢!
原文连接地址:React Diff 算法

相关文章
相关标签/搜索