如何解决Angular“10 $ digest()迭代到达”错误
达到10 $ digest()迭代。 中止!
在“最近5次迭代中发起的观察者”中有很多支持文本,但是很多这个文本是来自各种函数的Javascript代码。 有诊断这个问题的经验法则吗? 问题总是可以缓解的,还是有足够复杂的应用程序,这个问题应该被视为警告?
正如Ven所说的,你要么在每个$digest
循环中返回不同的(不相同的)对象,要么你要多次更改数据。
找出你的应用的哪个部分导致这种行为的最快解决scheme是:
- 删除所有可疑的HTML – 基本上从模板中删除所有的HTML,并检查是否没有警告
- 如果没有警告 – 添加一小部分你删除的HTML,并检查问题是否回来
- 重复第2步,直到你得到一个警告 – 你会找出你的HTML的哪个部分是负责的问题
- 进一步调查 – 步骤3中的部分负责变换
$scope
上的对象,或者在每个$digest
循环中返回不同的对象。 - 如果在步骤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数据或视图,则可能需要使用while
, for
或Array.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 })