95

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

有很多支持文本,例如“最近 5 次迭代中触发的观察者:”等,但其中很多文本是来自各种函数的 Javascript 代码。是否有诊断此问题的经验法则?这是一个总是可以缓解的问题,还是有足够复杂的应用程序,这个问题应该被视为一个警告?

4

13 回答 13

83

正如 Ven 所说,您要么在每个$digest周期返回不同(不相同)的对象,要么您更改数据太多次。

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

  1. 删除所有可疑的 HTML - 基本上从模板中删除所有 html,并检查是否没有警告
  2. 如果没有警告 - 添加您删除的 html 的一小部分并检查问题是否再次出现
  3. 重复第 2 步,直到您收到警告 - 您将确定 html 的哪一部分是导致问题的原因
  4. 进一步调查 - 步骤 3 中的部分负责$scope在每个$digest循环中改变对象或返回不同的对象。
  5. 如果您$digest在第 1 步之后仍然有迭代警告,那么您可能正在做一些非常可疑的事情。对父模板/范围/控制器重复相同的步骤

您还想确保您没有更改自定义过滤器的输入

请记住,在 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
于 2013-06-16T00:55:21.113 回答
73

通常,当您每次都返回不同的对象时会发生这种情况。

例如,如果您在 a 中使用它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在他们的网站上添加了一些更深入的解释

于 2013-06-14T19:56:59.637 回答
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;
    }
}
于 2014-07-26T05:22:31.090 回答
7

它也有可能根本不是无限循环。10 次迭代并不是一个足够大的数字,因此无法肯定地得出结论。因此,在进行疯狂追逐之前,最好先排除这种可能性。

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

如果您构建依赖于递归监视的数据或视图,您可能希望使用或搜索迭代解决方案(即不依赖于启动新的摘要循环while)。有时结构只是高度嵌套,甚至不是递归的,在这些情况下,除了提高限制外,可能没什么可做的。forArray.forEach

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

例如,如果您有一个在 a$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 以找到问题的根源,当然是有帮助的。

于 2016-08-16T17:53:45.760 回答
6

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

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

至:

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

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

于 2015-01-30T22:23:21.720 回答
3

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

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

在下面添加一行:

console.log("aaaa",watch)

然后刷新你的页面,在开发工具控制台中,你会发现你的错误代码。

于 2017-02-18T13:03:16.740 回答
1

这是一个已知的错误ui-router,这对我们有帮助:https ://github.com/angular-ui/ui-router/issues/600

于 2015-09-11T15:04:53.577 回答
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'
    };

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

很容易被忽略,因为错误信息非常神秘,而且看起来与真正的问题无关。

于 2016-07-31T04:47:12.603 回答
0

我在我的项目中遇到了这个问题,因为.otherwise()缺少我的路线定义并且我打错了路线。

于 2016-08-10T17:50:00.197 回答
0

我遇到了这个问题,因为我正在这样做

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

而不是这个:(注意= vs ===),我的单元测试开始中断,我发现我的愚蠢

var variableExpense = this.lodash.find(product.variableExpenseList, (ve) => {
               return ve.rawMaterial.id === rawMaterial.id;
});
于 2017-02-12T01:32:19.870 回答
0

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

$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">
于 2017-03-23T21:55:35.943 回答
0

这就是我接近它并找到解决方案的方式:我检查了文本,它显示:

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

观察者在最后 5 次迭代中触发: [[{"msg":"statement === statment && functionCall()","newVal":[{"id":7287,"referen...

所以如果你能看到

味精

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

于 2019-01-18T14:10:12.007 回答
-4

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

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

于 2017-10-12T11:14:32.583 回答