如何解决角度“10 $ digest()迭代达到”错误

时间:2013-06-14 19:43:01

标签: angularjs

  

达到10 $ digest()次迭代。中止!

在“最后5次迭代中发出的观察者”等意义上有很多支持文本,但是很多文本都是来自各种功能的Javascript代码。有诊断这个问题的经验法则吗?这是一个总是可以减轻的问题,还是应用程序很复杂,应该将此问题视为警告?

13 个答案:

答案 0 :(得分:74)

Ven说,你要么在每个$digest周期内返回不同的(不相同的)对象,要么就是在改变数据的次数太多了。

找出应用程序的哪个部分导致此行为的最快解决方案是:

  1. 删除所有可疑HTML - 基本上从模板中删除所有html,并检查是否没有警告
  2. 如果没有警告 - 添加你删除的html的一小部分并检查问题是否已经恢复
  3. 重复步骤2,直到收到警告 - 您将找出html的哪个部分负责此问题
  4. 进一步调查 - 步骤3中的部分负责变异$scope上的对象或在每个$digest周期返回不相同的对象。
  5. 如果您在步骤1之后仍然有$digest次迭代警告,那么您可能会做一些非常可疑的事情。对父模板/范围/控制器重复相同的步骤
  6. 您还希望确保不改变自定义过滤器的输入

    请记住,在JavaScript中,有一些特定类型的对象不像您通常期望的那样:

    new Boolean(true) === new Boolean(true) // false
    new Date(0) == new Date(0) // false
    new String('a') == new String('a') // false
    new Number(1) == new Number(1) // false
    [] == [] // false
    new Array == new Array // false
    ({})==({}) // false
    

答案 1 :(得分:71)

通常情况发生在每次返回不同的对象时。

例如,如果您在ng-repeat

中使用此功能
$scope.getObj = function () {
  return [{a: 1}, {b: 2}];
};

您将收到此错误消息,因为Angular尝试具有“稳定性”并将执行该函数,直到它返回相同的结果2次(与===相比),在我们的情况下将永远不会返回true,因为该函数始终返回一个新对象。

console.log({} === {}); // false. Those are two different objects!

在这种情况下,您可以通过直接在对象中存储对象来修复它,例如

$scope.objData = [{a: 1}, {b: 2}];
$scope.getObj = function () {
  return $scope.objData;
};

这样你总是会返回同一个物体!

console.log($scope.objData === $scope.objData); // true (a bit obvious...)

(即使在复杂的应用程序中,也不应该遇到这种情况。)

更新:Angular has added some more in-depth explanation on their website

答案 2 :(得分:11)

只是想把这个解决方案放在这里,希望它能帮助别人。我得到了这个迭代问题,因为我正在迭代生成的属性,每次调用它时都会创建一个新对象。

我通过在第一次请求时缓存生成的对象来修复它,然后总是返回缓存(如果它存在)。还添加了一个dirty()方法,它会根据需要破坏缓存的结果。

我有这样的事情:

function MyObj() {
    var myObj = this;
    Object.defineProperty(myObj, "computedProperty" {
        get: function () {
            var retObj = {};

            return retObj;
        }
    });
}

以下是解决方案的实施方法:

function MyObj() {
    var myObj = this,
        _cached;
    Object.defineProperty(myObj, "computedProperty" {
        get: function () {
            if ( !_cached ) {
                _cached = {};
            }

            return _cached;
        }
    });

    myObj.dirty = function () {
        _cached = null;
    }
}

答案 3 :(得分:6)

我遇到了同样的问题 - 我每次都在创建一个新日期。因此,对于处理日期的任何人,我转换了所有这样的调用:

var date = new Date(); // typeof returns object

为:

var date = new Date().getTime(); // typeof returns number

初始化数字而不是日期对象为我解决了这个问题。

答案 4 :(得分:4)

它也有可能根本不是无限循环。 10次​​迭代的数量不足以得出任何确定性的结论。因此,在进行野鹅追逐之前,最好先排除这种可能性。

最简单的方法是将最大摘要循环次数增加到更大的数量,这可以使用module.config方法在$rootScopeProvider.digestTtl(limit)方法中完成。如果infdig错误不再出现,您只需要一些足够复杂的更新逻辑。

如果您构建依赖于递归监视的数据或视图,您可能希望使用whilefor或{{1}搜索迭代解决方案(即不依赖于要启动的新摘要循环) }。有时结构只是高度嵌套而不是递归,除了提高限制外,在这些情况下可能没有太多工作要做。

调试错误的另一种方法是查看摘要数据。如果您打印JSON,则会得到一个数组数组。每个顶级条目代表一次迭代,每次迭代都包含一个监视条目列表。

例如,如果您拥有一个在Array.forEach上修改的属性,则很容易看到该值无限变化:

$watch
$scope.vm.value1 = true;
$scope.$watch("vm.value1", function(newValue)
{
    $scope.vm.value1 = !newValue;
});

当然,在较大的项目中,这可能不那么简单,尤其是因为如果监视是[ [ { "msg":"vm.value1", "newVal":true, "oldVal":false } ], [ { "msg":"vm.value1", "newVal":false, "oldVal":true } ], [ { "msg":"vm.value1", "newVal":true, "oldVal":false } ], [ { "msg":"vm.value1", "newVal":false, "oldVal":true } ], [ { "msg":"vm.value1", "newVal":true, "oldVal":false } ] ] 插值,msg字段通常具有值"fn: regularInterceptedExpression"

除了已经提到的方法,比如减少HTML以找到问题的根源,当然是有帮助的。

答案 5 :(得分:1)

ui-router中的已知错误,这有助于我们:https://github.com/angular-ui/ui-router/issues/600

答案 6 :(得分:1)

简单的方法是: 使用angular.js,而不是min文件。 打开它,找到这条线:

if ((dirty || asyncQueue.length) && !(ttl--)) {

在下面添加一行:

console.log("aaaa",watch)

然后刷新您的页面,在开发工具控制台中,您将 找到你的错误代码。

答案 7 :(得分:0)

我还想提一下,当我在项目中的自定义指令的templateUrl中输入错误时,我收到了此错误消息。由于拼写错误,无法加载模板。

/* @ngInject */
function topNav() {
    var directive = {
        bindToController: true,
        controller: TopNavController,
        controllerAs: 'vm',
        restrict: 'EA',
        scope: {
            'navline': '=',
            'sign': '='
        },
        templateUrl: 'app/shared/layout/top-navTHIS-IS-A-TYPO.html'
    };

查看网络浏览器的开发工具的网络标签,查看是否有任何资源出现404错误。

容易被忽视,因为错误信息非常含糊,似乎与真实问题无关。

答案 8 :(得分:0)

我在我的项目中遇到了这个问题,因为 .otherwise()错过了我的路线定义而且我遇到了错误的路线。

答案 9 :(得分:0)

我有这个问题因为我这样做了

var variableExpense = this.lodash.find(product.variableExpenseList, (ve) => {
               return ve.rawMaterial.id = rawMaterial.id;
});

而不是:( notice = vs ===),我的单元测试开始破坏,我发现了我的愚蠢

var variableExpense = this.lodash.find(product.variableExpenseList, (ve) => {
               return ve.rawMaterial.id === rawMaterial.id;
});

答案 10 :(得分:0)

我遇到了这个问题,我需要一个动态的工具提示...它导致角度每次重新计算它作为一个新值(即使它是相同的)。我创建了一个函数来缓存计算值,如下所示:

$ctrl.myObj = {
    Title: 'my title',
    A: 'first part of dynamic toolip',
    B: 'second part of dynamic tooltip',
    C: 'some other value',
    getTooltip: function () {
        // cache the tooltip
        var obj = this;
        var tooltip = '<strong>A: </strong>' + obj.A + '<br><strong>B: </strong>' + obj.B;
        var $tooltip = {
            raw: tooltip,
            trusted: $sce.trustAsHtml(tooltip)
        };
        if (!obj.$tooltip) obj.$tooltip = $tooltip;
        else if (obj.$tooltip.raw !== tooltip) obj.$tooltip = $tooltip;
        return obj.$tooltip;
    }
};

然后在html中,我这样访问它:

<input type="text" ng-model="$ctrl.myObj.C" uib-tooltip-html="$ctrl.myObj.getTooltip().trusted">

答案 11 :(得分:0)

这是我处理并找到解决方案的方式: 我检查了文本,显示为:

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!

观察者在最近5次迭代中解雇了:[[{{msg“:” statement === statement && functionCall()“,” newVal“:[{” id“:7287,” referent ...

所以如果您可以看到

  

味精

这就是产生错误的语句。我检查了此消息中调用的函数,我从所有函数中返回(false)只是为了确定哪个有问题。 其中一个正在调用一个函数,该函数会不断更改收益,这就是问题所在。

答案 12 :(得分:-2)

听起来很疯狂,我只是在突然重新启动时重新启动浏览器来修复此错误。

因此,一种解决方案是清除浏览器的缓存或尝试重新启动浏览器。