码迷,mamicode.com
首页 > 其他好文 > 详细

(十三)通过DOM事件DOMNodeRemoved,看ng-repeat的性能问题以及track by的作用

时间:2015-03-07 22:47:25      阅读:4776      评论:0      收藏:0      [点我收藏+]

标签:ng-repeat性能   track by的作用   

1.DOMNodeRemoved事件

DOMNodeRemoved事件这里不做过多介绍,有个大概的认识,会使用即可。如下代码给content对象注册了DOMNodeRemoved事件处理函数,当content下有子元素被删除的时候,就会触发DOMNodeRemoved事件。

<script>
	window.onload = function(){
		
		var dom = document.getElementById("content");
		dom.addEventListener("DOMNodeRemoved",function(event){
					
		});
	
	};
</script>
<body>
	<div id="content">
		<div></div>
		<!--commet-->
		<span></span>
	</div>
</body>


2.ng-repeat遍历的数组为空或者长度为0的时候

当ng-repeat遍历的数组为空或者长度为0的时候,会生成一个HTML注释。

<!doctype html>
<html lang="en">
	<head>
	   <meta charset="utf-8">
	   <title>ng-repeat</title>
	   <script src="jquery-1.11.1.js"></script>
	   <script src="angular-1.2.25.js"></script>
	   <script>			
			function wholeController($scope,$rootScope,$injector)
			{
				$scope.dataList = null;
				//$scope.dataList = [];
			}
	   </script> 
	</head>
	
	<body ng-app>
		<div ng-controller="wholeController">
			<div>begin</div>
			<div id="content">
				<div ng-repeat="item in dataList">{{item.name}}</div>
			</div>
			<div>end</div>
		</div>	
	</body>
</html>
ng-repeat生成的dom元素如下,就是一段html注释。

<div id="content">
	<!-- ngRepeat: item in dataList -->
</div>

3.ng-repeat中不使用track by子语句

由于angularjs数据的双向绑定特性,当scope中的数据发生改变的时候,会自动刷新界面。
<!doctype html>
<html lang="en">
	<head>
	   <meta charset="utf-8">
	   <title>ng-repeat</title>
	   <script src="jquery-1.11.1.js"></script>
	   <script src="angular-1.2.25.js"></script>
	   <script>
			$(function(){
				
				var domObject = $("#content").get(0);
				domObject.addEventListener("DOMNodeRemoved",function(event){
					console.log("some dom was deleted.");
				});
				
			});
			
			function wholeController($scope,$rootScope,$injector)
			{
				$scope.dataList = [ 
										{"id":1,"name":"a1"},
										{"id":2,"name":"a2"},
										{"id":3,"name":"a3"},
										{"id":4,"name":"a4"}
								  ];
				
				$scope.first = function(){
					$scope.dataList = [ 
										{"id":1,"name":"b1"},
										{"id":2,"name":"b2"},
										{"id":3,"name":"b3"},
										{"id":4,"name":"b4"}
									  ];
				
				}
			}
			
	   </script> 
	</head>
	
	<body ng-app>
		<div ng-controller="wholeController">
			<input type="button" value="first" ng-click="first();"/>
			<div>begin</div>
			<div id="content">
				<div ng-repeat="item in dataList">{{item.name}}</div>
			</div>
			<div>end</div>
		</div>	
	</body>
	
</html>
当点击first按钮的时候,scope中的dataList数据发生了变化,界面会自动刷新。如果要实现dom的刷新有2种方式:
方式一:删除之前所有存在的dom,然后重新生成dom。
方式二:重用之前的dom元素,仅仅更新dom元素的属性。

在没有使用track by的情况下,angular采用的是方式一,这一点可以通过我们注册的DOMNodeRemoved事件处理函数得到证实。我们知道dom的频繁操作是非常耗费性能的,那为什么 ng-repeat 不能利用已有的 dom 元素去更新数据呢?因为你没有把数组元素的标识属性告诉它,ng-repeat不知道怎么替换。在没有使用track by的情况下,我们可以看到 ng-repeat 往数组里每个元素加了一个 $$hashKey 的属性:
技术分享

这个 key 是由 Angular 内部的 nextUid() 方法生成,类似数据库自增,但是是使用字符串。现在我们明白了,因为每次替换数组都会导致 ng-repeat 为每个元素生成一个新 key, 所以根本没办法重用已有的 Dom 元素。那怎么解决这个问题呢?就是使用track by子语句。将ng-repeat改成下面的方式1或者方式2,就可以发现没有dom删除事件。

<!--方式1-->
<div ng-repeat="item in dataList track by item.id">{{item.name}}</div>

<!--方式2-->
<div ng-repeat="item in dataList track by $index">{{item.name}}</div>


4.数组长度未变,但是顺序发生了变化

上面的代码中,点击first按钮,dataList只是name属性值发生了改变,数组长度和顺序都没有发生变化。

[ 
	{"id":1,"name":"a1"},
	{"id":2,"name":"a2"},
	{"id":3,"name":"a3"},
	{"id":4,"name":"a4"}
];

变成

[ 
	{"id":1,"name":"b1"},
	{"id":2,"name":"b2"},
	{"id":3,"name":"b3"},
	{"id":4,"name":"b4"}
];


如果我们改变dataList中元素的顺序呢?

[ 
	{"id":1,"name":"a1"},
	{"id":2,"name":"a2"},
	{"id":3,"name":"a3"},
	{"id":4,"name":"a4"}
];

变成

[ 
	{"id":4,"name":"b1"},
	{"id":2,"name":"b2"},
	{"id":3,"name":"b3"},
	{"id":1,"name":"b4"}
];

下面这段代码中,我们改变dataList的顺序,然后使用track by $index和track by item.id看看是什么效果。

<!doctype html>
<html lang="en">
	<head>
	   <meta charset="utf-8">
	   <title>ng-repeat</title>
	   <script src="jquery-1.11.1.js"></script>
	   <script src="angular-1.2.25.js"></script>
	   <script>
			$(function(){
				
				var domObject = $("#content").get(0);
				domObject.addEventListener("DOMNodeRemoved",function(event){
					console.log("some dom was deleted."+event.target);
				});
				
			});
			
			function wholeController($scope,$rootScope,$injector)
			{
				$scope.dataList = [ 
										{"id":1,"name":"a1"},
										{"id":2,"name":"a2"},
										{"id":3,"name":"a3"},
										{"id":4,"name":"a4"}
								  ];
				
				$scope.first = function(){
					$scope.dataList = [ 
										{"id":4,"name":"b1"},
										{"id":2,"name":"b2"},
										{"id":3,"name":"b3"},
										{"id":1,"name":"b4"}
									  ];
				
				}
			}
			
	   </script> 
	</head>
	
	<body ng-app>
		<div ng-controller="wholeController">
			<input type="button" value="first" ng-click="first();"/>
			<div>begin</div>
			<div id="content">
				<div ng-repeat="item in dataList track by item.id">{{item.name}}</div>
				<!--
				<div ng-repeat="item in dataList track by $index">{{item.name}}</div>
				-->
			</div>
			<div>end</div>
		</div>	
	</body>
	
</html>

可以看到使用track by $index的时候,不会发生dom删除事件,即是更新dom元素, 而不是先删除再新建。当使用track by item.id的时候,会发生dom删除事件。也就是说,当数组中元素顺序改变的时候,使用track by item.id与不使用track by没有什么差别。大家可以试试看当数组的长度发生变化时,ng-repeat的表现是什么样子的。


参考文章:

http://www.cnblogs.com/MigCoder/p/3930264.html


(十三)通过DOM事件DOMNodeRemoved,看ng-repeat的性能问题以及track by的作用

标签:ng-repeat性能   track by的作用   

原文地址:http://blog.csdn.net/aitangyong/article/details/44106921

(0)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!