上一章介绍了数据双向绑定,那么在angularjs1.x版本中是怎么做到这一点的呢?就是依赖Dirty Checking,即本章介绍的脏检查。那么什么是脏检查?简而言之,就是在angularjs作用域内定义的变量发生变化时(在作用域内定义的所有变量都有一个watch,用于监听变量的状态),触发所有变量的循环检查(从根作用rootscope开始向内检查,即按锚的深度检查,每一次独立的循环检查为一次digest cycle),当检查到数据变更时,则同步数据(如果model中的数据发生变更,则向view同步,如果view中的数据发生变更,则向model同步),直到所有数据稳定。当所有数据稳定后,还会执行一次额外的全量检查。
接下来我们构造一个无限循环的场景来看一下脏检查是如何实现的,顺便看看当发生无限循环时,脏检查是如何处理的。构造两个对象以及对应的监听,对象1的监听器功能为:监听到对象1变更时,则修改对象2,对象2的监听器功能为:监听到对象2变更时,则修改对象1。
在c2.js中定义对象及监听:
/**
* Created by 李庆 on 2016/10/6.
*/
define(["jquery","../../../framework/service/httpService"],function($,httpService){
var c2Controller = ["$scope","maskService",function($scope,maskService){
$scope.test = function(){
console.log("enter controller");
};
$scope.getData = function(){
maskService.show("get data");
$.ajax({
"type":"GET",
"contentType":"application/json;charset=UTF-8",
//修改前为"url":"mock/test.json",
"url":httpService.getUrl("GET","/nova/test.json"),
"success":function(data){
console.log(JSON.stringify(data));
setTimeout(function(){
maskService.hide();
},6000);
},
"error":function(data){
console.log("error");
}
});
}
$scope.user1 = 0;
$scope.user2 = 0;
$scope.$watch(function() {
return $scope.user1;
}, function(oldResult, newResult) {
console.log("watch1 "+JSON.stringify($scope.user1));
console.log(JSON.stringify($scope.user2));
$scope.user2++;
});
$scope.$watch(function() {
return $scope.user2;
}, function(oldResult, newResult) {
console.log("watch2 "+JSON.stringify($scope.user1));
console.log(JSON.stringify($scope.user2));
$scope.user1++;
});
}];
return c2Controller;
});
变更部分内容如下:
在c2.html中显示对象信息:
<div>
<input type="button" value="test Controller" ng-click="test()">
<button ng-click="getData()">request</button>
<div>{{user1}}</div>
<div>{{user2}}</div>
</div>
变更部分内容如下:
然后来看一下页面的情况,user1和user2的值都是22:
那么,为什么值会是22呢?再看一下控制台信息(由于无限循环的原因,digest cycle理论上会一直执行下去,变量的值会一直递增,下图的控制台打印信息也可以看到前10次的digest cycle都正常执行):
然而从第11次digest cycle开始时,angularjs认为我们的代码一定发生了问题,终止了脏检查:
也就是说脏检查的digest cycle循环次数是有上限的,也就是10次,第11次则会抛出异常(虽然值还是变更了)。
如本章开头所说,当所有数据稳定后,还会执行一次额外的全量检查,所以,第二轮的digest cycle又开始了(即使前一次digest cycle循环终止的原因是达到了循环次数上限):
从第11次digest cycle开始时(即变量的值从21变更为22时),angularjs又终止了脏检查:
每一次独立的digest cycle都会从外向内检查所有变量并同步,当前一次的digest cycle触发了其他数据的变更,则会触发第二轮的digest cycle,直到第十一轮的digest cycle,达到digest cycle的循环上限,digest cycle循环终止。从这里可以看出,脏检查实际上是非常消耗资源的,在实际的项目开发过程中,需要尽量避免定义数据的多级联动,避免影响页面的可靠性和用户体验。