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

时间:2017-03-10 15:58:00

标签: javascript html 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>
&#13;
&#13;
&#13;

请注意,getText()函数运行两次,而过滤器只运行一次。我假设getText()函数运行两次以确保模型现在稳定。为什么过滤器的行为不一样?

5 个答案:

答案 0 :(得分:5)

关于这个主题的文件很清楚:

  

在模板中,过滤器仅在其输入已更改时执行。这比在每个$ digest上执行过滤器更有效,就像表达式一样。

Here's the source.

答案 1 :(得分:3)

Cosmin是完全正确的 - 这是一个演示来证明它(巧合的是,它会在某个时刻导致堆栈溢出) - 当调用getText()时,它会为输入分配一个新值。文本过滤器,导致它重新评估,这会导致另一个摘要周期,这会导致过滤器重新评估...这最终会导致堆栈溢出。

编辑我删除了导致溢出的测试部分 - 这只会让过滤器评估两次,因为只调用了两次getText。

&#13;
&#13;
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';
  };
});
&#13;
<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>
&#13;
&#13;
&#13;

答案 2 :(得分:1)

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

From AngularJS Docs:- 在模板中,过滤器仅在其输入已更改时执行。这比在每个$ digest上执行过滤器更有效,就像表达式一样。

此规则有两个例外:

  • 通常,这仅适用于采用原始值的过滤器 作为输入。接收对象作为输入的过滤器将在每个上执行 $ digest,因为跟踪输入是否成本太高 改变。
  • 标记为$ stateful的过滤器也会在每个$ digest上执行。有关详细信息,请参阅状态过滤器。请注意,没有AngularJS核心过滤器是$ stateful。

答案 3 :(得分:0)

根据documentation

  

过滤器仅在输入已更改时执行。这比在每个$digest上执行过滤器更高效,就像表达式一样。

     

此规则有两个例外:

     

通常,这仅适用于将原始值作为输入的过滤器。接收对象作为输入的过滤器将在每个$digest上执行,因为如果输入已更改,则跟踪成本太高。

     

标记为$stateful的过滤器也会在每个$digest上执行。有关详细信息,请参阅状态过滤器。请注意,没有AngularJS核心过滤器$stateful

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

答案 4 :(得分:0)

两个绑定都被检查两次,但是你只能看到一次被检查两次。在过滤器的情况下,输入是&#39;&#39;。 Angular只在脏检查时检查过滤器的INPUT(source)并检查两次并比较结果。所以它没有两次调用过滤器。

对于大括号绑定,表达式的RESULT被检查两次,因此您可以看到您的函数被调用两次。

但是如果你对过滤器输入一个类似this的函数,你会看到它被调用两次,就像你的花括号绑定一样,过滤器仍然只被调用一次。

将过滤器输入更改为函数会显示输入被选中两次,过滤器只被调用一次:

{{getText() | text}}