其实昨晚就遇到了这个问题。测试告诉我,在选择了某个数据作为筛选条件的时候。明明选择了某个条件,但是筛选失效。
我打开chrome浏览器,打断点查看是不是在选择了该条数据无法触发请求数据的方法正常执行。后来我发现,选择了条件是正常的。方法调用也是正常的,接口返回数据也是正常的。在一个search接口中添加一个卡ID的筛选条件之后,事实上筛选出来了只有6条数据。可是很明显,页面上的数据并不只有6条。一页20条数据,现在页面上的数据有上十页的分页。由于之前已经打断点查看过接口调用是成功的,那么唯一的一个就是angular本身的bug,导致数据无法更新。
结果在自己排查了N遍之后,去查看了控制台。于是乎就抛出了异常。点击该异常就在angular官网看到这个
$digest already in progress
以我拙略的英文水平可以理解到这句话的意思是$digest
方法已经在执行。其实我是看了csdn一位后端大神写的解释angular实现双向数据绑定原理之后才恍然大悟。这个错误的真正意思。我先说我的解决方案吧,既然提出这个报错。那么不难发现,是已经在执行$digest方法的时候又一次执行该方法,才会抛出该异常。故我将第二次的调用终止了,完美解决。
其实官网有解释,我自己虽然看得懂英文。但是需要好久去一个个理解单词。于是乎我就继续百度。百度到了’$apply()以及$digest()
’
看到了以为大神写的博客讲angular的这两个方法。其实angular实现双向数据绑定的原理是这样子的,使用它的时候需要讲数据绑定到scope对象上。然后angular会给scope对象上的所有属性添加一个watcher,这个watcher跟angular中的$watch方法一样。当它发现你的试图中有数据发生变化,那么在控制器中就会立马更新相关数据,同时反过来毅然。当你在控制器中更新scope中的属性对象的时候,也会实时的更新到view中。
等等,angular不是神。他是怎么知道控制器或者视图中数据发生了变化的呢?这时候就要提到 digest方法了。它会定期调用该方法去触发watcher来反馈是否有数据发生变化。其实上面的例子中事情是这样子发展的。在发生数据变化之后,angular会首先调用 scope. apply(),该方法会自动调用自动地调用 rootScope. digest()。 apply()方法有两种形式。第一种会接受一个function作为参数,执行该function并且触发一轮 digest循环。第二种会不接受任何参数,只是触发一轮 digest循环。我们马上会看到为什么第一种形式更好。
其实angular只能支持在上下文中的任何位置更新model上的数据自动调用 apply,如果你在上下文中以外的地方更新model的值,那么你需要手动调用 apply。如下的例子
setTimeout(function(){
$scope.name = 'fred';
console.log($scope.name);
},2000)
上面的例子中,在两秒中之后会自动打印出fred。但是在页面中绑定的name变量并不会实时更新。这时候你就需要手动调用该方法才能实现页面数据更新。代码如下
setTimeout(function(){
$scope.name = 'fred';
console.log($scope.name);
$scope.$apply(); // 这样会触发$digest实行新一轮的watcher然后页面数据更新
},2000)
note:以上其实可以直接调用
timeout方法来执行,该方法会自动调用
scope.$apply()
到此angular双向数据绑定的原理基本我了解了。
那么我遇到的问题说明了什么呢?我在一个异步中更新数据,在第一个$apply()方法未执行完成,又去异步调用了该方法。导致angular抛出异常。
以上是我的理解,可能原博写的要比我详细。csdn原博地址:http://blog.csdn.net/dm_vincent/article/details/38705099
英文原文:http://www.sitepoint.com/understanding-angulars-apply-digest/