在页面中如何大面积操作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. Codeforces Round #205 (Div. 2) : A

    题意: 要求找到最少次数的交换次数使得两组数都是偶数: 很明显答案要么是0,要么是1,或者不管怎么交换都不行(-1): 所以: #include<cstdio> #define maxn ...

  2. VS2015中的项目类图

    发现右键项目的时候,是没有类图的. https://msdn.microsoft.com/en-us/library/hyxd8c85.aspx 右键项目--添加--新建项. 选择类图. 然后将整个项 ...

  3. java String 去除空格

    1. java 去掉字符串的空格(中间空格,左右空格) 比如 时间字符串,去掉‘-’,‘:’,与空格 String x = "2008-09-08 11:12:23"; x=x.r ...

  4. js 的 提交

    <script type="text/javascript"> function sub(){ if(document.form1.xingming.value==&q ...

  5. HDOJ/HDU 2561 第二小整数(水题~排序~)

    Problem Description 求n个整数中倒数第二小的数. 每一个整数都独立看成一个数,比如,有三个数分别是1,1,3,那么,第二小的数就是1. Input 输入包含多组测试数据. 输入的第 ...

  6. Android学习笔记(四)深入探讨Activity

    在应用程序中至少包含一个用来处理应用程序的主UI功能的主界面屏幕.这个主界面一般由多个Fragment组成,并由一组次要Activity支持.要在屏幕之间切换,就必须要启动一个新的Activity.一 ...

  7. [JIT_APP]Java基础知识总结

    一.Java语言的基础知识 1. 开发Java语言的公司 美国Sun(Sum Microsystems)公司开发.   2.Java的3个版本 J2SE(Java2 Standard Edition) ...

  8. xrdp远程 & watchdog 启用与测试 & WebRTC

    sudo apt-get install xrdp sudo apt-get install vnc4server tightvncserver echo "xfce4-session&qu ...

  9. appium api

    AppiumDriver getAppStrings()      默认系统语言对应的Strings.xml文件内的数据.iOS driver.getAppStrings(Stringlanguage ...

  10. c++ 流基本概念

    前言 在程序经常实现数据的输入和输出,c++通过一种称为流(stream)的机制提供了更为精良的输入和输出方法.流是一种灵活且面向对象的I/o方法. 根据操作对象不同分为文件流.字符串流.控制台流. ...