为什么AngularJS过滤器只运行一次?

4
请考虑以下示例:

    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()函数运行两次是为了确保模型现在稳定。为什么过滤器的行为不同呢?
5个回答

5

文档在这个问题上非常清楚:

在模板中,只有当输入发生变化时,过滤器才会被执行。这比每次 $digest 中表达式都执行过滤器更有效率。

源码在这里。


3

Cosmin说得很对,这里有一个演示可以证明(可能会在某个时候导致堆栈溢出),当调用getText()时,它会给文本过滤器的输入分配一个新值,这会导致它重新评估,进而引起另一个脏检查周期,从而导致该过滤器再次被评估......最终可能会导致类似堆栈溢出的问题。


编辑:我删除了一个导致溢出的测试部分-由于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>


1
当表达式在模板中使用时,AngularJS首先评估花括号内的内容/文本(插值),然后将该值/输出转换为字符串,再将此字符串值插入HTML元素/属性中。
{{link1:来自AngularJS文档:-}} 在模板中,仅当它们的输入发生更改时,才执行过滤器。这比在每个$ digest上执行过滤器要更高效。
有两个例外:
  • 通常,这仅适用于以原始值作为输入的过滤器。接收对象作为输入的过滤器在每个$ digest上执行,因为跟踪输入是否已更改的成本太高。
  • 标记为$ stateful的过滤器也在每个$ digest上执行。有关更多信息,请参见Stateful filters。请注意,没有AngularJS核心过滤器是$ stateful。

0
根据文档
过滤器仅在其输入发生更改时才执行。这比表达式在每个$digest上执行过滤器要更高效。
有两个例外:
通常,这仅适用于以原始值作为输入的过滤器。接收对象作为输入的过滤器在每个$digest上执行,因为跟踪输入是否已更改会太昂贵。
标记为$stateful的过滤器也在每个$digest上执行。有关更多信息,请参见Stateful filters。请注意,没有AngularJS核心过滤器是$stateful的。
由于您具有不变的原始值,因此无需再次执行过滤器。将空字符串''更改为对象文字{},然后查看发生了什么;)

0

两个绑定都被检查了两次,但你只能看到其中一个被检查了两次。在过滤器的情况下,输入是''。Angular 只在脏检查时检查 INPUT(source) 到过滤器,并检查它两次并比较结果。所以它不会调用过滤器两次。

对于花括号绑定,表达式的结果被检查了两次,因此你可以看到你的函数被调用了两次。

但如果你将过滤器的输入改为像 this 这样的函数,你会发现它被调用了两次,就像你的花括号绑定一样,而过滤器仍然只被调用了一次。

将过滤器输入更改为函数后,显示输入被检查了两次,而过滤器仅被调用了一次:

{{getText() | text}}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接