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

bla*_*ter 89 angularjs

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

"Watchers在最后5次迭代中解雇了"等意义上有很多支持文本,但是很多文本都是来自各种函数的Javascript代码.有诊断这个问题的经验法则吗?这是一个总是可以减轻的问题,还是应用程序很复杂,应该将此问题视为警告?

g00*_*0fy 78

正如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
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!这是一个有用的启发式方法.我也在想,Angular为ngRepeat提供的新"追踪"功能对我也有帮助.我在服务中使用Underscore做了一些map()和groupBy()的东西,所以每次都肯定会返回"不同"的对象(即使它们在逻辑上代表相同的东西 - "Id by track"会帮助Angular看不到它们如果他们没有真正的"改变". (5认同)
  • 如果你正在做`map()`和`groupBy()`而不是shure你的`$ watch`es通过`objectEquality``执行脏检查$ watch('myFunctionDoingGropby',callback,true)`参见http:// docs.angularjs.org/api/ng.$ro​​otScope.Scope#$watch (2认同)

Ven*_*Ven 72

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

例如,如果您在以下位置使用此功能ng-repeat:

$scope.getObj = function () {
  return [{a: 1}, {b: 2}];
};
Run Code Online (Sandbox Code Playgroud)

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

console.log({} === {}); // false. Those are two different objects!
Run Code Online (Sandbox Code Playgroud)

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

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

这样你总是返回相同的对象!

console.log($scope.objData === $scope.objData); // true (a bit obvious...)
Run Code Online (Sandbox Code Playgroud)

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

更新:Angular 在其网站上添加了一些更深入的解释.

  • 确保在每次通话时都没有创建不同的对象;). (2认同)

Asm*_*mor 11

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

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

我有这样的事情:

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

            return retObj;
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

以下是实施的解决方案:

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

            return _cached;
        }
    });

    myObj.dirty = function () {
        _cached = null;
    }
}
Run Code Online (Sandbox Code Playgroud)


H.B*_*.B. 7

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

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

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

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

例如,如果您有一个$watch在自身上修改的属性,则很容易看到该值正在无限变化:

$scope.vm.value1 = true;
$scope.$watch("vm.value1", function(newValue)
{
    $scope.vm.value1 = !newValue;
});
Run Code Online (Sandbox Code Playgroud)
[
   [
      {
         "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
      }
   ]
]
Run Code Online (Sandbox Code Playgroud)

当然,在较大的项目中,这可能不那么简单,特别是因为如果手表是插值,该msg字段通常具有价值。"fn: regularInterceptedExpression"{{ }}

除此之外,已经提到的方法,例如削减 HTML 以找到问题的根源,当然是有帮助的。


Arm*_*tov 6

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

var date = new Date(); // typeof returns object
Run Code Online (Sandbox Code Playgroud)

至:

var date = new Date().getTime(); // typeof returns number
Run Code Online (Sandbox Code Playgroud)

初始化数字而不是日期对象为我解决了它.