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

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

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

正如Ven所说的,你要么在每个$digest循环中返回不同的(不相同的)对象,要么你要多次更改数据。

找出你的应用的哪个部分导致这种行为的最快解决scheme是:

  1. 删除所有可疑的HTML – 基本上从模板中删除所有的HTML,并检查是否没有警告
  2. 如果没有警告 – 添加一小部分你删除的HTML,并检查问题是否回来
  3. 重复第2步,直到你得到一个警告 – 你会找出你的HTML的哪个部分是负责的问题
  4. 进一步调查 – 步骤3中的部分负责变换$scope上的对象,或者在每个$digest循环中返回不同的对象。
  5. 如果在步骤1之后仍然有$digest迭代警告,那么比起你可能做了一件非常可疑的事情。 对父模板/作用域/控制器重复相同的步骤

您还要确保不会改变自定义filter的input

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

 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 

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

例如,如果你在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 在他们的网站上增加了一些更深入的解释 。

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

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

我有这样的事情:

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

这里是解决scheme的实现:

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

我也有同样的问题 – 我每次都在创build一个新的date。 所以对于任何处理date的人来说,我都会转换所有的电话:

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

至:

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

初始化一个数字而不是一个date对象为我解决了它。

也有可能不是一个无限循环。 10次​​迭代不是一个足够大的数字来得出任何确定的结论。 因此,在进行野鹅追逐之前,首先排除这种可能性是明智的。

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

如果您依靠recursionArray.forEach来构build数据或视图,则可能需要使用whileforArray.forEach来search迭代解决scheme(即不依赖新的摘要循环来启动)。 有时结构是高度嵌套的,甚至不是recursion的,除了提高极限以外,在这些情况下可能没有太多的工作要做。

debugging错误的另一种方法是查看摘要数据。 如果你漂亮的打印JSON,你会得到一个数组的数组。 每个顶层条目代表一个迭代,每个迭代由一个监视条目列表组成。

例如,如果你有一个在$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"

除此之外,已经提到的方法,比如减lessHTML以find问题的根源,当然是有帮助的。

这是在ui-router的一个已知的bug,这有助于我们: https : //github.com/angular-ui/ui-router/issues/600

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

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

在下面添加行:

 console.log("aaaa",watch) 

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

我还想提一下,当我在我的项目中使用的自定义指令的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' }; 

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

容易忽略,因为错误信息是非常神秘的,似乎与真正的问题无关。

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

我有这个问题,因为我正在这样做

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

而不是:(通知= VS ===),我的unit testing开始打破,我发现我的愚蠢

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

我遇到了这个问题,我需要一个dynamic的工具提示…它导致angular度重新计算每次作为一个新的价值(即使它是相同的)。 我创build了一个caching计算值的函数,如下所示:

 $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"> 

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

所以一个解决scheme就是清除浏览器的caching或尝试重新启动浏览器。

将此代码添加到您的应用程序定义或app.js

 yourApp.config(function ($rootScopeProvider) { $rootScopeProvider.digestTtl(15); // 15 is int value, just set to more than 10. If not works justincrement it bye one every-time and refresh page to test })