【问题标题】:angularjs infinite $digest Loop when no scope changes没有范围变化时的angularjs无限$digest循环
【发布时间】:2013-11-08 16:23:30
【问题描述】:

我的角度代码出现以下错误。我很难理解为什么函数 getDrawWithResults 会导致摘要循环,因为似乎没有任何副作用?它只是从列表中返回属性设置为 true 的项目。

只有在页面上第一次使用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: []"]]

这是我的代码:

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

// return list of draws with results
$scope.getDrawsWithResults = function(draws) {
    return _.filter(draws, function(draw){
        return draw.results && draw.results.length > 0;
    });
}

【问题讨论】:

    标签: javascript angularjs infinite-loop


    【解决方案1】:

    我假设_.filter 每次运行时都会返回一个新的数组实例。这会导致 Angular 的隐含 $watches 像:

    ng-hide="getDrawsWithResults(selectedLottery.draws)"
    

    ng-repeat="draw in getDrawsWithResults(selectedLottery.draws)"
    

    认为模型发生了变化,因此需要再次消化。

    我会实现filter

    app.filter('withResults', function() {
        return function(draws) {
            return _.filter(draws, function(draw){
                return draw.results && draw.results.length > 0;
            });
        }
    })
    

    并像这样应用它(见下面的编辑):

    ng-hide="selectedLottery.draws | withResults"
    

    ng-repeat="draw in selectedLottery.draws | withresults"
    

    在 cmets 讨论后编辑

    实际的问题是这个绑定:

    ng-hide="getDrawsWithResults(selectedLottery.draws)"
    

    ng-hide 注册了一个手表,该手表将永远触发,因为过滤数组的引用总是改变。可以改成:

    ng-hide="getDrawsWithResults(selectedLottery.draws).length > 0"
    

    以及相应的过滤器:

    ng-hide="(selectedLottery.draws | withResults).length > 0"
    

    ng-repeat 没有同样的问题,因为它注册了一个$watchCollection

    【讨论】:

    • 这似乎仍然会导致同样的问题?错误:[$rootScope:infdig] 达到 10 个 $digest() 迭代。中止!观察者在最后 5 次迭代中触发:[["selectedLottery.draws|withResults; newVal: []; oldVal: []"],["selectedLottery.draws|withResults; newVal: []; oldVal: []"],[ "selectedLottery.draws|withResults; newVal: []; oldVal: []"],["selectedLottery.draws|withResults; newVal: []; oldVal: []"],["selectedLottery.draws|withResults; newVal: [ ]; oldVal: []"]]
    • 查看here。然后,注释掉前 2 个抽奖,看看 ng-hide 也可以。正如预期的那样,withResults 过滤器在每个绑定中被调用 2 次。你能做一个类似的 plunker 来重现这个问题吗?
    • 查看使用getDrawsWithResults(您的原始代码)的this version。显然它也有效,所以我认为新数组弄乱了 Angular 的摘要的假设是不正确的。我认为问题出在其他地方。也许selectedLotterryselectedLotterry.draws 在摘要期间会发生某种变化。
    • 我最终通过编写一个返回布尔值的新函数来修复它。我想我也可以通过 !!getDrawsWithResults(selectedLottery.draws).length 来修复它,这也会返回一个布尔值
    • 好的...现在我看到了这个错误。 ng-repeatselectedLottery.draws 数组上注册一个 $scope.$watchCollection。这意味着它监控它的元素而不是实际参考。另一方面,ng-hide 注册了一个$scope.$watch 并接受通过一些启发式测试评估为true 的东西(一个名为toBoolean 的私有函数。每次数组引用更改时,该手表都会触发,即 总是所以摘要失败。我也会编辑我的答案。
    【解决方案2】:

    这意味着$scope.getDrawsWithResults() 不是幂等的。给定相同的输入和状态,它不会始终返回相同的结果。并且ng-hide 需要一个幂等函数(就像 Angular 监视的所有函数一样)。

    简而言之,您最好使用返回单个布尔结果的函数,而不是返回数组的_.filter。也许_.all

    幂等性之所以重要,是因为 Angular 的 $digest 循环的工作方式。由于您的ng-hide,Angular 会监视您的$scope.getDrawsWithResults() 的结果。这样,每当它应该重新评估 ng-hide 时,它就会收到警报。你的ng-repeat 不受影响,因为它的结果不需要被 Angular 监视。

    所以每次 $digest 发生时(每秒多次)$scope.getDrawsWithResults() 都会被调用,以查看它的结果是否与之前的 $digest 周期相比发生了变化,因此它是否应该更改 ng-hide。如果结果发生了变化,Angular 知道这也可能意味着它正在监视的其他一些函数(可能使用你函数的结果)可能已经发生了变化。所以它需要重新运行 $digest (如果需要,让更改通过系统传播)。

    所以 $digest 会一直运行,直到它所观察的所有函数的结果都停止变化。或者直到有 10 个 $digest 循环。 Angular 假设如果系统在 10 个周期后不稳定,它可能永远不会稳定。所以它放弃并抛出你得到的错误信息。

    如果您愿意,可以在这里更深入地了解这一切:http://teropa.info/blog/2013/11/03/make-your-own-angular-part-1-scopes-and-digest.html

    【讨论】:

    • 你是不是说它不是幂等的,因为它每次都不会返回相同的数组?即使数组具有相同的内容。这对我来说很有意义。我给科斯答案,但只是因为他建议如何解决这个问题。
    • 如果认为@KayakDave 应该得到答案,因为他发现问题出在ng-hide 上。我认为问题通常是绑定到返回不同值的函数调用的概念(无论如何我都很难避免)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-16
    • 2023-03-24
    • 1970-01-01
    相关资源
    最近更新 更多