框架操作DOM和原生js操作DOM比较
问题引出
对于Angular和React操作DOM的速度,和原生js操作DOM的速度进行了一个比较:
代码如下:
<!DOCTYPE html> <html ng-app="test">
<head>
<title>Performance Comparison for Knockout, Angular and React</title>
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/css/bootstrap.css" rel="stylesheet" />
<style type="text/css">
* { box-sizing:border-box; }
body { padding:30px 0; }
h2 { margin:0; margin-bottom:25px; }
h3 { margin:0; padding:0; margin-bottom:12px; }
.test-data { margin-bottom:3px; }
.test-data span { padding:3px 10px; background:#EEE; width:100%; float:left; cursor:pointer; }
.test-data span:hover { background:#DDD; }
.test-data span.selected { background:#3F7AD9; color:white; } .time { font-weight:bold; height:26px; line-height:26px; vertical-align:middle; display:inline-block; cursor:pointer; text-decoration:underline; }
</style> <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.3/angular.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/react/0.12.1/react.js"></script>
<script type="text/javascript">
console.timeEnd("build"); document.addEventListener("DOMContentLoaded", function() {
_knockout();
_react();
_raw();
}); _angular(); function _buildData(count) {
count = count || 1000; var adjectives = ["pretty", "large", "big", "small", "tall", "short", "long", "handsome", "plain", "quaint", "clean", "elegant", "easy", "angry", "crazy", "helpful", "mushy", "odd", "unsightly", "adorable", "important", "inexpensive", "cheap", "expensive", "fancy"];
var colours = ["red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "orange"];
var nouns = ["table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger", "pizza", "mouse", "keyboard"];
var data = [];
for (var i = 0; i < count; i++)
data.push({id: i+1, label: adjectives[_random(adjectives.length)] + " " + colours[_random(colours.length)] + " " + nouns[_random(nouns.length)] });
return data;
} function _random(max) {
return Math.round(Math.random()*1000)%max;
} function _knockout() {
ko.applyBindings({
selected: ko.observable(),
data: ko.observableArray(), select: function(item) {
this.selected(item.id);
}, run: function() {
var data = _buildData(),
date = new Date(); this.selected(null);
this.data(data);
document.getElementById("run-knockout").innerHTML = (new Date() - date) + " ms";
}
}, document.getElementById("knockout")); } function _angular(data) {
angular.module("test", []).controller("controller", function($scope) {
$scope.run = function() {
var data = _buildData(),
date = new Date(); $scope.selected = null;
$scope.$$postDigest(function() {
document.getElementById("run-angular").innerHTML = (new Date() - date) + " ms";
}); $scope.data = data;
}; $scope.select = function(item) {
$scope.selected = item.id;
};
});
} function _react() {
var Class = React.createClass({
select: function(data) {
this.props.selected = data.id;
this.forceUpdate();
}, render: function() {
var items = [];
for (var i = 0; i < this.props.data.length; i++) {
items.push(React.createElement("div", { className: "row" },
React.createElement("div", { className: "col-md-12 test-data" },
React.createElement("span", { className: this.props.selected === this.props.data[i].id ? "selected" : "", onClick: this.select.bind(null, this.props.data[i]) }, this.props.data[i].label)
)
));
} return React.createElement("div", null, items);
}
}); var runReact = document.getElementById("run-react");
runReact.addEventListener("click", function() {
var data = _buildData(),
date = new Date(); React.render(new Class({ data: data, selected: null }), document.getElementById("react"));
runReact.innerHTML = (new Date() - date) + " ms";
});
} function _raw() {
var container = document.getElementById("raw"),
template = document.getElementById("raw-template").innerHTML;
document.getElementById("run-raw").addEventListener("click", function() {
var data = _buildData(),
date = new Date(),
html = ""; for (var i = 0; i < data.length; i++) {
var render = template;
render = render.replace("{{className}}", "");
render = render.replace("{{label}}", data[i].label);
html += render;
} container.innerHTML = html; var spans = container.querySelectorAll(".test-data span");
for (var i = 0; i < spans.length; i++)
spans[i].addEventListener("click", function() {
var selected = container.querySelector(".selected");
if (selected)
selected.className = "";
this.className = "selected";
}); document.getElementById("run-raw").innerHTML = (new Date() - date) + " ms";
});
} ko.observableArray.fn.reset = function(values) {
var array = this();
this.valueWillMutate();
ko.utils.arrayPushAll(array, values);
this.valueHasMutated();
};
</script>
</head>
<body ng-controller="controller">
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Performance Comparison for React, Angular and Knockout</h2>
</div>
</div> <div class="col-md-3">
<div class="row">
<div class="col-md-7">
<h3>React</h3>
</div>
<div class="col-md-5 text-right time" id="run-react">Run</div>
</div>
<div id="react"></div>
</div> <div class="col-md-3">
<div class="row">
<div class="col-md-7">
<h3>Angular</h3>
</div>
<div class="col-md-5 text-right time" id="run-angular" ng-click="run()">Run</div>
</div>
<div>
<div class="row" ng-repeat="item in data">
<div class="col-md-12 test-data">
<span ng-class="{ selected: item.id === $parent.selected }" ng-click="select(item)">{{item.label}}</span>
</div>
</div>
</div>
</div> <div id="knockout" class="col-md-3">
<div class="row">
<div class="col-md-7">
<h3>Knockout</h3>
</div>
<div class="col-md-5 text-right time" id="run-knockout" data-bind="click: run">Run</div>
</div>
<div data-bind="foreach: data">
<div class="row">
<div class="col-md-12 test-data">
<span data-bind="click: $root.select.bind($root, $data), text: $data.label, css: { selected: $data.id === $root.selected() }"></span>
</div>
</div>
</div>
</div> <div class="col-md-3">
<div class="row">
<div class="col-md-7">
<h3>Raw</h3>
</div>
<div class="col-md-5 text-right time" id="run-raw">Run</div>
</div>
<div id="raw"></div>
</div>
</div> <script type="text/html" id="raw-template">
<div class="row">
<div class="col-md-12 test-data">
<span class="{{className}}">{{label}}</span>
</div>
</div>
</script>
</body>
</html>
DOM Render
运行结果:

原生最快,为什么还要用框架?
问题分析
框架封装了很多操作,为了提升可维护性,会进行分层,只提供出API。很多应用其实类似,为了提升可读性可复用性,往往会分层、封装,单一的简单应用上性能上可能并不会有明显提升。但是,对于复杂的需要很多模块的应用,框架的优势就很明显。在不用自己优化性能的同时,可维护性也较好。框架会尽最大程度保证性能。复杂的情况,比如多次更新一块DOM,或者多块DOM同时更新等等。
React的VirtualDOM
如果没有VirtualDOM的情况下,想重置DOM,需要使用innerHTML.一个大型列表的数据如果都变更了,那么重置所有DOM无可厚非,但是更多的情况是,只有几个数据变更了,这种情况下,重新渲染大片DOM,就有些浪费了。
可以比较下虚拟DOM和innerHTML的差异:

框架操作DOM和原生js操作DOM比较的更多相关文章
- 原生js操作Dom节点:CRUD
知识点,依然会遗忘.我在思考到底是什么原因.想到研究生考试准备的那段岁月,想到知识体系的建立,知识体系分为正向知识体系和逆向知识体系:正向知识体系可以理解为教科书目录,逆向知识体系可以理解考试真题. ...
- 原生js操作dom的方法
今天学习了原生js的dom节点的操作,就记录下来,仅供自己以后参考. 1)创建节点:除了可以使用createElement创建元素,也可以使用createTextNode创建文本节点. documen ...
- 原生JS获取DOM 节点到浏览器顶部的距离或者左侧的距离
关于js获取dom 节点到浏览器顶/左部的距离,Jquery里面有封装好的offset().top/offset().left,只到父级的顶/左部距离position().top/position() ...
- 关于Echarts的原生js获取DOM元素与动态加载DOM元素的冲突问题
1.前言: 最近在做的看板项目,因为需要循环加载后台数据,并且用Echarts做数据呈现,所以jQuery和angular等库统统靠边站,Echarts用的是原生js获取DOM元素,至于诸多不兼容等深 ...
- 原生JS 实现 dom ready
记录一下项目技术问题: 记得:放在head标签内的脚本,第一时间执行 var baseTools = { // dom ready ready: function( f ){ var ie = !!( ...
- ThinkPHP 表单提交操作成功后执行JS操作如何刷新父页面或关闭当前页等操作
ThinkPHP 表单提交操作成功后执行JS操作如何刷新父页面或关闭当前页等操作 .操作成功后刷新父页面 $this->assign('jumpUrl', "javascript:wi ...
- 抛开jQuery,拾起原生JS的DOM操作
常用的JS-DOM操作与jQuery的对比 jQuery用多了,还是需要来熟练熟练原生JS的操作,不然写JS都快离不开jQuery了 目录 1. 获取DOM 2. 创建DOM 3. 添加DOM 4. ...
- 原生js封装dom操作库
var utils = (function(window) { var flag = "getComputedStyle" in window; function win(attr ...
- 原生js操作DOM基础-笔记
原文参考http://mp.weixin.qq.com/s?__biz=MzU3MDA0NTMzMA==&mid=2247485490&idx=1&sn=15197b4b53e ...
随机推荐
- 如何在Eclipse中设置默认的JSP文件头部编码
如何在Eclipse中设置默认的JSP文件头部编码 一般,我们为了以后在导入和导出程序的时候(特别是项目较大,文件多)一般都默认文件编码格式为UTF-8 如果你通常都是通过Eclipse来编写程序,那 ...
- H.264 / MPEG-4 Part 10 White Paper-翻译
1. Introduction Broadcast(广播) television and home entertainment(娱乐) have been revolutionised(彻底改变) b ...
- 百度之星热身赛-1001(dfs拓扑排序)
题意:作为年度优秀魔法学员的奖赏,哈利得到了一台具有魔力的计算机.这台计算机一旦开始处理某个任务,就会一直处理到这个任务结束为止(所以你可以认为它是单线程的).有一天,这台计算机得到了n个任务要处理, ...
- Day17_集合第三天
1.HashSet类(掌握) 1.哈希值概念 哈希值:哈希值就是调用对象的hashCode()方法后返回的一个int型数字 哈希桶:简单点理解就是存储相同哈希值对象的一个容器 1. ...
- viewPager动态加载listview数据
废话不多说,先上效果图.(代码见附件) 代码是修改自某大神的,我做了很多修改,之前只能向右滑动,现在可以左右无限滑动,只要数据没加载完就可以一直滑动.过程不算复杂,代码主要的地方都有注释. 附件dem ...
- hdu4691 Front compression ——暴力 || 后缀数组
link:http://acm.hdu.edu.cn/showproblem.php?pid=4691 暴力,数据明显太水了吧,n=10^5, O(n^2)的复杂度哎喂.想让大家暴力写直接让n=100 ...
- UML学习笔记
目前转岗到业务开发,业务逻辑用到了大量的类库.UML则是理解.指导其代码实现的利器. 有6种重要的关系,按照关系的强弱排序如下: 实现 = 泛化 > 组合(关联) >聚合 > 依赖 ...
- 生成new, old的 shell script
#!/bin/bash #usage: ./create_dts_diff_v2.x.sh path1 path2 __new_dir=$1 __old_dir=$2 #=============== ...
- asp.net使用My97 Date Picker时设置默认起始时间为n年之前的今天
可以使用My97 Date Picker组件来收集用户输入的日期值. 首先下载该组件:http://www.my97.net/dp/index.asp放到自己的项目中. 然后在项目里面引用js和css ...
- IOS开发-属性动画和关键帧动画的使用
CAMediaTiming是一个协议(protocol),CAAnimation是所有动画类的父类,但是它不能直接使用,应该使用它的子类. 继承关系: CoreAnmiation 核心动画 简写CA ...