在页面中如何大面积操作DOM的话,性能肯定是一个很大的问题,然而聪明的ReactJS实现了Virtual DOM技术,这是他的亮点之一。将组件的DOM结构映射到这个Virtual DOM对象上,并且ReactJS还实现了一套Diff算法,这也是他亮点之一。当需要更新组件的时候,会通过Diff算法找到要变更的内容,最后,在把这个修改更新到实际的DOM节点上,所以,组件更新实际上不是真的渲染整个DOM树,而是指更新需要修改的DOM节点,这样在性能上会比原生DOM快很多。

那么这个Virtual DOM到底是什么?假设我们要创建一个组件,其结构如下:

 <ul>
<li>
A
</li>
<li>
<ul>
<li>
B
</li>
</ul>
</li>
</ul>

然后我们开始创建原生组件:

 //用JSX实现的
var root = <ul>
<li>A</li>
<li>
<ul>
<li>
B
</li>
</ul>
</li>
</ul>;
//用javascript实现的
var A = React.createElement('li',null,'A');
var B = React.createElement('ul',null,React.createElement('li',null,'B'));
var root = React.createElement('ul',null,A,B);
//输出虚拟的DOM结构
console.log(root);

打开控制台我们就能看到输出的一个javascript的对象,没错这就是我们所说的Virtual DOM对象;

接下来我们看看Diff算法在ReactJS中的体现,首先我们借助浏览器中的MutationObderver功能,对页面元素进行监听

 'use strict';
const mutation = window.MutationObserver
||window.WebKitMutationObserver
||window.MozMutationObserver;
if(!!mutation){
const mutationObserver = new mutation((item) => {
item.forEach((item) => {
console.log(item);
});
});
const options = {
"childList" : true,
"attributes" : true,
"characterData" : true,
"subtree" : true,
"attributeOldValue" : true,
"characterDataOldValue" : true
};
mutationObserver.observe(document.body,options);
}

然后再把ReactJS组件的生命周期进行封装,便于组件来调用

 'use strict';
const LifeCycle = name => {
let obj = {
name : name
};
return Object.assign(obj,Cycle);
};
const Cycle = {
getDefaultProps:function(){
console.log(this.name,'getDefaultProps');
return {};
},
getInitialState:function(){
console.log(this.name,'getInitailState');
return {};
},
componentWillMount:function(){
console.log(this.name,'componentWillMount');
},
componentDidMount:function(){
console.log(this.name,'componentDidMount');
},
componentWillRecieveProps:function(){
console.log(this.name,'componentWillRecieveProps');
},
shouldComponentUpdate:function(){
console.log(this.name,'shouldComponentUpdate');
return true;
},
componentWillUpdate:function(){
console.log(this.name,'componentWillUpdate');
},
componentDidUpdate:function(){
console.log(this.name,'componentDidUpdate');
},
componentWillUnmount:function(){
console.log(this.name,'componentWillUnmount');
}
};

接着定义需要用到的组件

 'use strict';
//A组件
let A = React.createClass({
mixins:[LifeCycle('A')],
render:function(){
console.log('A','render');
return (
<ul>
<li>A</li>
<li>
<ul>
{this.props.children}
</ul>
</li>
</ul>
);
}
});
//B组件
let B = React.createClass({
mixins:[LifeCycle('B')],
render:function(){
console.log('B','render');
return (
<li>B</li>
);
}
});
//C组件
let C = React.createClass({
mixins:[LifeCycle('C')],
render:function(){
console.log('C','render');
return (
<li>C</li>
);
}
});
//D组件
let D = React.createClass({
mixins:[LifeCycle('D')],
render:function(){
console.log('D','render');
return (
<li>D</li>
);
}
});

最后,定义我们的主逻辑

 console.log('----------------first-----------------');
React.render(
<A><B></B><C></C></A>,
document.body
); setTimeout(() => {
console.log('-----------------second--------------');
React.render(
<A><B></B><D></D><C></C></A>,
document.body
);
},1000);

常规的做法就是将B和C组件先删除,然后依次创建和插入A,B,C组件。接下来我们打开浏览器的控制台看下ReactJS是怎么做的

          

从日志中可以看出,React的Diff算法的结果是,A组件不变,先将C组件进行删除,然后在创建D组件并插入D组件,最后创建并插入C组件,这比我们常规的做法省去了对B组件的删除操作。这样其实并没有将Diff算法的作用发挥到极限。下面我们调整下逻辑代码:

 console.log('----------------first-----------------');
React.render(
<A key="A"><B key="B"></B><C key="C"></C></A>,
document.body
); setTimeout(() => {
console.log('-----------------second--------------');
React.render(
<A key="A"><B key="B"></B><D key="D"></D><C key="C"></C></A>,
document.body
);
},1000);

主要的修改就是给每个组件加了一个key属性,此时再来运行下代码看下控制台的日志:

       

可以看出,这次Diff算法与之前的有很大的不同。B组件不变,C组件不变,只是在C组件之前创建并插入了D组件。

以上便是Virtual DOM和Diff算法的一些简单的使用和分析,学习来源:

http://calendar.perfplanet.com/2013/diff/ 《React Native入门与实践》

为什么选择我--ReactJS的更多相关文章

  1. 一看就懂的ReactJs入门教程-精华版

    现在最热门的前端框架有AngularJS.React.Bootstrap等.自从接触了ReactJS,ReactJs的虚拟DOM(Virtual DOM)和组件化的开发深深的吸引了我,下面来跟我一起领 ...

  2. 前端构建大法 Gulp 系列 (二):为什么选择gulp

    系列目录 前端构建大法 Gulp 系列 (一):为什么需要前端构建 前端构建大法 Gulp 系列 (二):为什么选择gulp 前端构建大法 Gulp 系列 (三):gulp的4个API 让你成为gul ...

  3. ReactJS webpack实现JS模块化使用的坑

    从一个原生HTML/CSS/JS模式的网页改造到ReactJS模块化的结构,需要以下步骤: (1)引用ReactJS框架 ->(2)使用webpack 工具 -> (3)配置webpack ...

  4. reactjs 接入数据模型以及markdown语法的支持

    页面如下: reactjs 数据接入,直接定义数据(json),如下: reactjs 数据接入,从服务器抓取数据(json),如下:  

  5. 初探ReactJS.NET 开发

    ReactJS通常也被称为"React",是一个刚刚在这场游戏中登场的新手.它由Facebook创建,并在2013年首次发布.Facebook认为React在处理SPA问题上可以成 ...

  6. ReactJs笔记

    中文教程:http://reactjs.cn/ 实例: http://www.ruanyifeng.com/blog/2015/03/react.html

  7. redux的中间层 --reactjs学习

    React只负责UI层,也就是我们通常在MVC框架中 所说的View层,所以在使用React开发中 我们得引入Redux 负责Model 一开始学习Redux的中间层 有点 摸不到头, 其实只要你注意 ...

  8. 初识ReactJs(一)

    React的开发背景 ReactJS官网地址:http://facebook.github.io/react/ Github地址:https://github.com/facebook/react J ...

  9. D2.Reactjs 操作事件、状态改变、路由

    下面内容代码使用ES6语法 一.组件的操作事件: 1.先要在组件类定义内定义操作事件的方法,如同event handler.若我需要监听在组件内的Button的点击事件onClick,首先定义监听方法 ...

随机推荐

  1. CMD 模块定义规范

    在 Sea.js 中,所有 JavaScript 模块都遵循 CMD(Common Module Definition) 模块定义规范.该规范明确了模块的基本书写格式和基本交互规则. 在 CMD 规范 ...

  2. bzoj 1257: [CQOI2007]余数之和sum 数学 && 枚举

    1257: [CQOI2007]余数之和sum Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 1779  Solved: 823[Submit][Sta ...

  3. windows下NGINX和PHP配合(FASTCGI)

    昨天测试了TOMCAT,今天考查了NGINX. 按网上说的作,比较简单. http://www.cnblogs.com/huayangmeng/archive/2011/06/15/2081337.h ...

  4. 转-[Python 学习]2.5版yield之学习心得

    在 shhgs 发布了关于< Py 2.5 what’s new 之 yield>之后,原来我不是特别关注 yield 的用法,因为对于2.3中加入的yield相对来说功能简单,它是作为一 ...

  5. h.264 scanning process for transform coefficients

    宏块在经过变换.量化后,得到大小为4x4或者8x8的矩阵,矩阵中的数据被称为transform coefficient levels.这些level在后面会被用于熵编码,因此我们需要把矩阵按照一定顺序 ...

  6. highestAvailable比较灵活,毕竟大多数功能不需要系统最高权限(四种方法:屏蔽UAC,右键以管理员身份运行,增加manisfest,制作数字证书)

    打开VS2005.VS2008.VS2010工程,查看工程文件夹中的Properties文件夹下是否有app.manifest这个文件:如没有,按如下方式创建:鼠标右击工程在菜单中选择“属性”,点击工 ...

  7. Guava学习

    Guava学习笔记目录 Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concu ...

  8. 【CF】304 E. Soldier and Traveling

    基础网络流,增加s和t,同时对于每个结点分裂为流入结点和流出结点.EK求最大流,判断最大流是否等于当前总人数. /* 304E */ #include <iostream> #includ ...

  9. linux安装JDK TOMCAT

    1.下载包 到http://apr.apache.org/下载下面3个包 apr-1.4.2.tar.gz apr-iconv-1.2.1.tar.gz apr-util-1.3.10.tar.gz  ...

  10. poj 1704 Georgia and Bob(阶梯博弈)

    Georgia and Bob Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 8656   Accepted: 2751 D ...