为什么我的Angular.js控制器在下面的代码中执行了两次它的函数?

Why does my Angular.js controller executes its function twice in the following code?

本文关键字:两次 函数 执行 js Angular 我的 控制器 在下面 代码 为什么      更新时间:2023-09-26

我有一个ng-repeat在一个属于SomeController的对象数组中循环:

<div ng-controller="SomeController as aCtrl">
  <div ng-repeat="category in aCtrl.categories">
    <p ng-show="aCtrl.checkShouldBeDisplayed(category)">{{category.name}}</p>
  </div>
</div>

控制器定义为:

app.controller('SomeController', function() {
this.categories = [{
  "name": "one",
}, {
  "name": "two",
}, {
  "name": "three",
}, {
  "name": "four",
}];
this.counter = 0;
this.checkShouldBeDisplayed = function(channel) {
  this.counter = this.counter + 1;
  console.log("executing checkShouldBeDisplayed " + this.counter);
  return true;
};
}); 

我希望checkShouldBeDisplayed函数计数为4,因为SomeController.categories数组中有四个元素。相反,它计数为8 -在这里检查:http://plnkr.co/edit/dyvM49kLLTGof9O92jGb(您需要查看浏览器中的控制台以查看日志)。我怎样才能避免这种行为呢?干杯!

这是预期的;指令ng-repeat将重复多少次,框架认为是正确的;这被称为脏检查,你可以在这篇文章中读到更多关于它的内容。

由于这个原因,最好是声明性的思考而不是命令式的思考。换句话说,方法checkShouldBeDisplayed应该只做它在罐头上说的,而不依赖于它被调用的次数。如果您需要执行某种类型的聚合或操作,则应该在控制器的其他地方完成。

根据的文档:

watchExpression在每次调用$digest()时被调用,并且应该返回将被监视的值。(由于$digest()在检测到变化时会重新运行,因此watchExpression可以对$digest()执行多次,并且应该是幂等的。)
[…]
手表侦听器可能会更改型号,这可能会触发其他侦听器。这是通过重新运行监视程序,直到没有检测到任何更改来实现的。

所有ngShow所做的就是注册一个观察者:

scope.$watch(attr.ngShow, function ngShowWatchAction(value){
    $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
});

您的函数是ngShow的watch-expression,因此执行两次:
1. 在第一个$digest中,它检测新值。
2. 在第二个$digest中,它验证没有任何更改并终止。


在这个简短演示中,您可以验证有两个$digest循环。