使用 angular 指令会导致错误:达到 10 次 $digest() 迭代。中止

Posted

技术标签:

【中文标题】使用 angular 指令会导致错误:达到 10 次 $digest() 迭代。中止【英文标题】:Using angular directive causes error: 10 $digest() iterations reached. Aborting 【发布时间】:2016-11-15 08:11:25 【问题描述】:

http://plnkr.co/edit/dBe36L6vwOZOykujFRfg

在 plunker 中,我收到以下角度错误:“已达到 10 个 $digest() 迭代。正在中止!”

该逻辑在 index.html 中使用时有效:

<h1>(working) Fruit from main document: vm.randomFruit().name</h1>

但是当我尝试使用传入的对象调用指令中的类似代码时抛出错误:

<h1>(causing error) Fruit from directive template: fruit.name</h1>

如果我只是在范围函数中执行此操作,它似乎也不会在指令中引发错误:

//this works for both instances
return vm.fruits[0];

但是,当我以任何方式触摸 $scope.fruits 时,即使只是复制它,它也会在指令版本上出现错误。

//something about touching the array here exposes the error, even though it still works
var x = [];
angular.copy(vm.fruits, x);
return x[0];

为什么这里会抛出这个错误?似乎是某种循环依赖,但为什么只在指令版本上呢?

有没有更好的方法来使用更标准的指令、模板和传入的参数对象?

错误:达到 10 次 $digest() 迭代。中止!观察者开枪 最后 5 次迭代: [["fn: parentValueWatch; newVal: \"名称\":\"苹果\"; oldVal: \"name\":\"apple\""],["fn: 父值观察; newVal: \"名称\":\"苹果\";旧值: \"name\":\"apple\""],["fn: parentValueWatch;新值: \"名称\":\"苹果\"; oldVal: \"name\":\"apple\""],["fn: 父值观察; newVal: \"名称\":\"苹果\";旧值: \"name\":\"apple\""],["fn: parentValueWatch;新值: \"名称\":\"苹果\"; oldVal: \"name\":\"apple\""]] 在错误(本机) 在 Object.$digest (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:7925:19) 在 Object.$apply (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:8097:24) 完成后 (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:9111:20) 在完成请求 (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:9274:7) 在 XMLHttpRequest.xhr.onreadystatechange (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js:9244:11)


更新 1

将 aFruit() 更新为 randomFruit() 以便更好地展示我的问题:

$scope.randomFruit = function() 
//something about touching the array here exposes the error, even though it still works
var x = [];
angular.copy($scope.fruits, x);
//do some custom stuff here, sorting, etc. <whatever>
var randomIndex = Math.floor((Math.random() * x.length));
return x[randomIndex];
;

更新 2

被告知不要使用 $scope,因此将其从控制器中完全删除。仍然看到同样的错误。

myApp.controller('FruitCtrl', function() 
  var vm = this;
  vm.fruits = fruits;

  vm.randomFruit = function() 
    //something about touching the array here exposes the error, even though it still works
    var x = [];
    angular.copy(vm.fruits, x);
    //do some custom stuff here, sorting, etc. <whatever>
    var randomIndex = Math.floor((Math.random() * x.length));
    return x[randomIndex];
  ;
);

【问题讨论】:

【参考方案1】:

问题在于方法,如何将数据传递给 Angular。 Angular 有很棒的数据绑定,它会检查模型是否改变并更新 UI。更新 UI 后,它会再次检查下一轮更改。如果数据一直在变化,它可能会卡在循环中。

在这种特殊情况下,Angular 不理解数据是相同的。它在每个摘要循环中接收新数组并假定数据已更改,更新 UI 并再次开始检查。

确保您没有在每个 $digest 循环中从 UI 更新数组或在每个 $digest 循环上返回新数组。 例如 这将调用无限循环:

$scope.aFruit= function() 
  return [
  "name":"apple",
  "name":"orange",
  "name":"banana",
];
;

这将正常工作,因为对数组的引用保持不变

var myFruits =   return [
      "name":"apple",
      "name":"orange",
      "name":"banana",
    ]    
$scope.aFruit= function() 
    myFruits;
    ;

【讨论】:

JanisP 是正确的,这就是我假设你想要它做的事情:plnkr.co/edit/cFchj9uxVZRj5Fe8L5Al?p=preview 另外,我建议您查看 Angular 1.5 中的新组件方法,这是更简洁的指令。 plnkr.co/edit/7leRr2TfoVOSfdVjxNK0?p=preview @hsiung - 不,简单地返回第一个元素不是我的意思。这是一个更复杂的函数,例如从数组中返回一个随机元素或对数组进行排序并从中返回顶部 值。我已经更新了原始问题,以便更好地理解我的观点。 @Buchannon Update 1 仍然是同一件事 - 您在每个摘要周期都重新创建并返回新数组。它导致无限循环。尽量不要在视图中使用作用域函数,它们在屏幕渲染时会执行多次(尝试在它们中抛出断点以查看它们是如何工作的) @JanisP 更新 2,我摆脱了所有 $scope 引用,但仍然看到同样的问题。如果我需要一个动态的(计算的)属性并传递给指令,它似乎会抛出这个错误。【参考方案2】:

哦,好的,明白了! 有两种方法可以做到这一点,但我相信您正在寻找这种方法。

http://plnkr.co/edit/E1y9nqh0DdaHGW2hi4AM?p=preview

问题是您的方法正在返回一个对象,但您想获取字符串值。所以我们把方法改成这样:

$scope.randomFruit = function() 
  var x = [];
  angular.copy($scope.fruits, x);
  var randomIndex = Math.floor((Math.random() * x.length));
  return x[randomIndex].name;
;

接下来,我们需要更改我们的组件绑定以接受带有“@”的字符串

bindings:  fruit: '@' ,

最后,我们需要调用模板中的方法,并使用插值将其设置为我们传递给组件的值:

<show-fruit fruit=randomFruit() />

希望这会有所帮助,还有另一种方法,但是如果您想在 in 模板中调用您的方法,这就是您必须这样做的方式。

【讨论】:

不错的尝试,但我想将整个对象传递给模板,而不仅仅是属性之一。我知道模板现在只使用“名称”属性,但这是一个非常简化的示例,说明我正在尝试在另一个项目中使用我的代码库。 好的,所以如果您尝试传入整个对象,则无法复制它。这就是贾尼斯最初所说的。您在每个摘要周期都生成一个新对象,因此 angular 不知道何时停止。 - 您可以使用 '&' 绑定传递函数并在指令中调用函数 - 在控制器中调用函数并将输出分配给范围变量,然后将该新对象传递给指令 - 您可以执行 Janis 的操作做了并将逻辑放在指令中 - 或者您可以对原始集合进行操作(即不要复制它)

以上是关于使用 angular 指令会导致错误:达到 10 次 $digest() 迭代。中止的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2 编写结构指令,如 ngFor、iterableDiffer 可能会导致错误

Angular2-signaturepad 与 Angular 一起使用会导致找不到模块错误

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

Angular JS:IE 错误:达到 10 次 $digest() 迭代。中止

Angular 2 绑定到计算的 getter 会导致调试错误

将 BEM CSS 与 Angular 指令一起使用