javascript 当范围没有变化时,angularjs 无限 $digest 循环
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19863873/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
angularjs infinite $digest Loop when no scope changes
提问by foiseworth
I'm getting the below error in my angular code. I'm struggling to understand why the function getDrawWithResults would cause a digest cycle as there don't seem to be any side effects? It just returns items from a list that have a property set to true.
我的角度代码中出现以下错误。我正在努力理解为什么函数 getDrawWithResults 会导致消化循环,因为似乎没有任何副作用?它只是从列表中返回属性设置为 true 的项目。
The error only occurs when the first use of getDrawWithResults is on the page, if I remove, the error stops.
错误仅在页面上第一次使用 getDrawWithResults 时发生,如果我删除,错误就会停止。
Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [["getDrawsWithResults(selectedLottery.draws); newVal: []; oldVal: []"],["getDrawsWithResults(selectedLottery.draws); newVal: []; oldVal: []"],["getDrawsWithResults(selectedLottery.draws); newVal: []; oldVal: []"],["getDrawsWithResults(selectedLottery.draws); newVal: []; oldVal: []"],["getDrawsWithResults(selectedLottery.draws); newVal: []; oldVal: []"]]
This is my code:
这是我的代码:
HTML
HTML
<h4 ng-cloak ng-hide="getDrawsWithResults(selectedLottery.draws)">Results of Selected Lottery</h4>
<div class="con" ng-repeat="draw in getDrawsWithResults(selectedLottery.draws)" ng-cloak>
<h5 class="con__header">[[ draw.date|date:'EEEE d MMMM yyyy - H:mm' ]]</h5>
<div class="balls-list__outer con__row">
<div class="balls-list">
<div class="balls-list__ball__outer" ng-repeat="b in draw.results">
<button class="balls-list__ball btn btn-con">[[ b ]]</button>
</div>
</div>
</div>
</div>
JS
JS
// return list of draws with results
$scope.getDrawsWithResults = function(draws) {
return _.filter(draws, function(draw){
return draw.results && draw.results.length > 0;
});
}
回答by Kos Prov
I assume _.filter
returns a new array instance everytime it is run. This causes angular's implicit $watch
es like:
我假设_.filter
每次运行时都会返回一个新的数组实例。这会导致 angular 的隐式$watch
es,例如:
ng-hide="getDrawsWithResults(selectedLottery.draws)"
and
和
ng-repeat="draw in getDrawsWithResults(selectedLottery.draws)"
to think that the model has changed so it needs to digest again.
认为模型发生了变化,因此需要再次消化。
I would implement a filter
我会实现一个过滤器
app.filter('withResults', function() {
return function(draws) {
return _.filter(draws, function(draw){
return draw.results && draw.results.length > 0;
});
}
})
and apply it like that (see EDIT below):
并像这样应用它(见下面的编辑):
ng-hide="selectedLottery.draws | withResults"
and
和
ng-repeat="draw in selectedLottery.draws | withresults"
EDITED after discussion in comments
在评论中讨论后编辑
The actual problem is this binding:
实际问题是这个绑定:
ng-hide="getDrawsWithResults(selectedLottery.draws)"
ng-hide
registers a watch which will fire forever since the reference of the filtered array always changes. It can be changed to:
ng-hide
注册一个手表,它将永远触发,因为过滤后的数组的引用总是改变。可以改为:
ng-hide="getDrawsWithResults(selectedLottery.draws).length > 0"
and the corresponding filter:
和相应的过滤器:
ng-hide="(selectedLottery.draws | withResults).length > 0"
ng-repeat
does not have the same problem because it registers a $watchCollection
.
ng-repeat
没有同样的问题,因为它注册了$watchCollection
.
回答by KayakDave
This implies $scope.getDrawsWithResults()
is not idempotent. Given the same input and state it doesn't consistently return the same result. And ng-hide
requires an idempotent function (as do all function that Angular has a watch on).
这意味着$scope.getDrawsWithResults()
不是幂等的。给定相同的输入和状态,它不会始终返回相同的结果。并且ng-hide
需要一个幂等函数(就像 Angular 有监视的所有函数一样)。
In short, you may be better off using a function that returns a single boolean result instead of _.filter
which returns an array. Perhaps _.all
?
简而言之,最好使用返回单个布尔结果的函数而不是_.filter
返回数组的函数。也许_.all
?
The reason idempotence matters here is because of the way Angular's $digest cycle works. Because of your ng-hide
Angular places a watch on the results of your $scope.getDrawsWithResults()
. This way it can be alerted whenever it should re-evaluate that ng-hide
. Your ng-repeat
is not affected because it's results don't need to be watched by Angular.
幂等性在这里很重要的原因是因为 Angular 的 $digest 循环的工作方式。因为你的ng-hide
Angular 会关注你的$scope.getDrawsWithResults()
. 这样,只要它应该重新评估它,它就会收到警报ng-hide
。您ng-repeat
不会受到影响,因为它的结果不需要被 Angular 监视。
So every time a $digest happens (which is many times a second) $scope.getDrawsWithResults()
is called to see if it's results changed from the previous $digest cycle and thus whether it should change ng-hide
. If the result has changed Angular knows that could also mean some other function it's watching (which possibly uses a result from your function) could have changed. So it needs to re-run $digest (letting the change propagate through the system if need be).
因此,每次 $digest 发生时(每秒多次)都会$scope.getDrawsWithResults()
被调用以查看它的结果是否与前一个 $digest 循环发生了变化,从而是否应该更改ng-hide
。如果结果发生了变化,Angular 知道这也可能意味着它正在监视的其他一些函数(可能使用您的函数的结果)可能已经发生了变化。所以它需要重新运行 $digest (如果需要,让更改通过系统传播)。
And so $digest keeps running until the results of all functions it's watching stop changing. Or until there's been 10 $digest cycles. Angular assumes that if the system isn't stable after 10 cycles it probably will never stabilise. And so it gives up and throws the error message you got.
所以 $digest 会一直运行,直到它正在观察的所有函数的结果停止改变。或者直到有 10 个 $digest 循环。Angular 假设如果系统在 10 个周期后不稳定,它可能永远不会稳定。所以它放弃并抛出你得到的错误信息。
You can dive into this all in more depth here if you'd like: http://teropa.info/blog/2013/11/03/make-your-own-angular-part-1-scopes-and-digest.html
如果您愿意,可以在此处更深入地了解这一切:http: //teropa.info/blog/2013/11/03/make-your-own-angular-part-1-scopes-and-digest。 html