为什么AngularJS过滤只能运行一次



考虑以下示例:

    angular.module('app', []).controller('TestController', function($scope) {
      $scope.getText = function() {
          console.log('getting text');
          return 'text';
      };
  }).filter('text', function() {
      return function() {
          console.log('text filter');
          return 'text';
      };
  });
 
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
<div ng-app="app" ng-controller="TestController">
    <p>{{getText()}}</p>
    <p>{{'' | text}}</p>
</div>

请注意,getText()功能运行两次,而过滤器仅运行一次。我假设getText()功能运行两次,以确保模型现在稳定。为什么不适合过滤器?

该文档在此主题上很清楚:

在模板中,过滤器仅在更改输入时执行。与表达式一样,这比在每个$摘要上执行过滤器更具性能。

这是源。

cosmin是完全正确的 - 这是一个证明它的演示(偶然地,在某个时候会导致堆栈溢出) - 当调用getText()时,它将分配一个新值对于文本过滤器的输入,这会导致其重新评估,从而导致另一个消化周期,从而导致过滤器重新评估...最终导致堆栈溢出。


edit 我删除了引起溢出的测试部分 - 这仅将过滤器评估两次,因为GetText仅称为两次。

angular.module('app', []).controller('TestController', function($scope) {
  $scope.foo = 'bar';
  $scope.getText = function() {
    console.log('getting text');
    $scope.foo += 'a';
    return 'text';
  };
}).filter('text', function() {
  return function() {
    console.log('text filter');
    return 'text';
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
<div ng-app="app" ng-controller="TestController">
  <p>{{getText()}}</p>
  <p>{{foo | text}}</p>
</div>

当在模板中使用表达式时,AngularJS首先评估括号内的材料/文本(插值),然后将值/输出转换为字符串,然后将此字符串值插入html元素/属性。

来自Angularjs文档: - 在模板中,仅在更改输入时执行过滤器。与表达式一样,这比在每个$摘要上执行过滤器更具性能。

此规则有两个例外:

  • 通常,这仅适用于采用原始值的过滤器作为输入。接收对象作为输入的过滤器在每个上执行$摘要,因为如果输入有更改。
  • 在每个$摘要上也执行标记为$ stateful的过滤器。有关更多信息,请参见状态过滤器。请注意,没有AngularJS核心过滤器是$状态的。

根据文档,

仅在更改输入时执行过滤器。与表达式一样,这比在每个$digest上执行过滤器更具性能。

此规则有两个例外:

通常,这仅适用于将原始值作为输入的过滤器。在每个$digest上执行接收对象的过滤器,因为要跟踪输入是否已更改,这太昂贵了。

在每个$digest上也执行了标记为$stateful的过滤器。有关更多信息,请参见状态过滤器。请注意,没有AngularJS核心过滤器是$stateful

由于您的原始值不会改变,因此过滤器不必再次执行。将空字符串''更改为对象字面的{},看看会发生什么;)

两个绑定都被检查两次,但是您只能看到两次检查。对于过滤器,输入为"。Angular仅在肮脏检查时将输入(源)检查到过滤器,然后检查两次并比较结果。因此,它不会两次调用过滤器。

对于卷曲支撑绑定,表达式的结果被检查两次,因此您可以看到两次称为功能。

但是,如果将过滤器输入到这样的函数,您会看到它被称为两次,就像您的卷曲支撑绑定一样,并且过滤器仍然只称为一次。

将过滤器输入更改为函数,显示输入两次,仅调用过滤器一次:

{{getText() | text}}

最新更新