React介绍

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

它采用声明式范例,可以传递声明代码,最大限度地减少与DOM的交互。

特点:

  1. 声明式设计:React采用声明范式,你可以轻松描述你的应用
  2. 高效:React通过对DOM的模拟表现,最大限度地较少与DOM的交互。
  3. 灵活:React可以与你所知道的库或框架很好地工作。

在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的一大核心技术,了解其实现原理对于灵活应用有着很大帮助。

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 Algorithm

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

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

React分三种情景:

a. 分层对比

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

b. 基于key匹配

Keys是一个VNode的唯一识别,用于对两个不同的VTree中的VNode做匹配的。通过key锁定某个组件后,React就可以直接对比这两个差异DOM节点树,复杂度为O(n)。

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

c. 基于自定义元素做优化

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 没有更新, 也不需要重新绘制。

React Diff 算法的更多相关文章

  1. react diff算法浅析

    diff算法作为Virtual DOM的加速器,其算法的改进优化是React整个界面渲染的基础和性能的保障,同时也是React源码中最神秘的,最不可思议的部分 1.传统diff算法计算一棵树形结构转换 ...

  2. React Diff算法

    Web界面由DOM树来构成,当其中某一部分发生变化时,其实就是对应的某个DOM节点发生了变化.在React中,构建UI界面的思路是由当前状态决定界面.前后两个状态就对应两套界面,然后由React来比较 ...

  3. React——diff算法

    react的diff算法基于两个假设: 1.不同类型的元素会产生不同的树 2.通过设置key,开发者能够提示那些子组件是稳定的 diff算法 当比较两个树时,react首先会比较两个根节点,接下来具体 ...

  4. React Diff算法一览

    前言 diff算法一直是React系统最核心的部分,并且由于演化自传统diff,使得比较方式从O(n^3)降级到O(n),然后又改成了链表方式,可谓是变化万千. 传统Diff算法 传统diff算法需要 ...

  5. React基础(Diff算法,属性和状态)

    1.React的背景原理 (1)React Diff算法流程 (2)React虚拟DOM机制 React引入了虚拟DOM(Virtual DOM)的机制:在浏览器端用Javascript实现了一套DO ...

  6. ReactiveNative学习之Diff算法

    React 源码剖析系列 - 不可思议的 react diff深入浅出React(四):虚拟DOM Diff算法解析React diff 算法总结链接引用的文章React出于性能的考虑,为了避免频繁操 ...

  7. React 源码剖析系列 - 不可思议的 react diff

      简单点的重复利用已有的dom和其他REACT性能快的原理. key的作用和虚拟节点 目前,前端领域中 React 势头正盛,使用者众多却少有能够深入剖析内部实现机制和原理. 本系列文章希望通过剖析 ...

  8. 直接操作DOM一定比虚拟DOM操作耗时,diff算法,key值,虚拟 DOM的定义

    直接操作DOM一定比虚拟DOM操作耗时吗? 或者一次直接DOM操作一定比一次虚拟DOM操作耗时吗? 1)虚拟DOM的本质就是一个JS对象,虚拟DOM减少了真实DOM的操作,当修改数据的时候,就是修改虚 ...

  9. diff算法深入一下?

    文章转自豆皮范儿-diff算法深入一下 一.前言 有同学问:能否详细说一下 diff 算法. 简单说:diff 算法是一种优化手段,将前后两个模块进行差异化比较,修补(更新)差异的过程叫做 patch ...

随机推荐

  1. 第六章并发编程,异步执行框架executor

    异步执行框架executor是一个接口,只有一个方法.接受一个Runnable做为参数,执行任务. 将任务的执行与提交解耦. 1:executor package java.util.concurre ...

  2. 中文乱码—Servlet—SpringMVC

    一.SpringMVC中的中文乱码问题 a:处理全局请求的中文乱码(配置Web.xml的字符编码过滤器) <filter> <filter-name>encodingFilte ...

  3. 20155316 2016-2017-2 《Java程序设计》第8周学习总结

    教材学习内容总结 课堂部分要点 数据结构与算法 与 Java相结合 collection API:数据结构 crypt:密码学 操作系统 考试部分重点 实验楼:Linux第四节 教材:第6章.第14章 ...

  4. 向Oracle 数据表中插入一条带有日期类型的数据

    有一张表:batch(批次表) 表的字段如下: 第一种情况: 现在需要插入一条当前的系统时间 sql 如下: insert into batch (batch_id, cus_id, batch_nu ...

  5. Centos75下samba搭建配置

    工作中,很经常需要把Linux服务器上的文件共享到windows上面,这时候需要在Linux服务器上安装samba套件. samba服务很好的实现了windows和linux之间的文件共享. 下面配置 ...

  6. 前端学习笔记之JavaScript

    JavaScript概述 JavaScript的历史 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中),后将其改名ScriptEase(客 ...

  7. PHP多进程学习(二)__fork起多个子进程,父进程的阻塞与非阻塞

    先简单来了解一下多进程 [来初步了解一下PHP多进程及简单demo] php的多进程是不是可以无限制的fork子进程?fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的 ...

  8. GreenOpenPaint的实现(六)图片的保存和打开

    如果只是直接的图片保存和打开,是没有很多内容的.但是我这里,将EXIF的信息融入其中,使得图像处理的结果能够保存下来.这样就非常有价值意义了. 所有的操作都放在DOC中进行处理. 我之前已经对EXIF ...

  9. 20145326 《Java程序设计》实验一实验报告

    北京电子科技学院(besti)实验报告 课程:Java程序设计 班级:1453 指导教师:娄嘉鹏 实验日期:2016.04.08 实验名称:Java开发环境的熟悉(Linux + Eclipse) 实 ...

  10. CCNA学习指南 -开放最短路径优先OSPF(多区域部分)

    在之前的介绍中,可以看到单区域OSPF对于古老的RIP的优点: 路由选择更新流量减小 使用与大型网络和链路速度不一样的网络 OSPF能够在LSDB中呈现网络拓扑结构,这使得它汇聚的速度远快于RIP. ...