2017-03-10 34 views
4

考虑下面的例子:为什么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()函数运行两次以确保模型现在稳定。为什么过滤器的行为不一样?

回答

5

文档是对这个问题很清楚:

在模板中,当他们的投入已经改变滤波器只能执行。这比在表达式中对每个$摘要执行过滤器更有效。

Here's the source.

1

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

From AngularJS Docs:- 在模板中,过滤器仅在其输入发生更改时才执行。这比在表达式中对每个$摘要执行过滤器更有效。

有两种情况例外:

  • 一般而言,这仅适用于取原始值 作为输入滤波器。接收对象作为输入的过滤器将在每个摘要上执行,因为如果输入已更改 ,跟踪成本太高。
  • 标记为$ stateful的过滤器也会在每个$摘要中执行。有关更多信息,请参阅状态过滤器。请注意,没有AngularJS核心过滤器是$ stateful。当它们的输入已经改变
0

作为每documentation

过滤器仅执行。这比在表达式中对每个$digest执行过滤器更有效。

有两种情况例外:

一般而言,这仅适用于采取原始值作为输入滤波器。接收对象作为输入的过滤器将在每个$digest上执行,因为跟踪输入是否更改成本太高。

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

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

3

科斯明是完全正确的 - 这里是一个演示,以证明这一点(其中,巧合的是,会造成在某些时候堆栈溢出) - 时的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>

0

两个绑定正在检查两次,但你只能看到一个被检查两次。在过滤器的情况下,输入是“”。角仅检查输入(source)到过滤器时脏检查和它检查两次,并比较结果。因此,它不会调用过滤器的两倍。

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

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

改变输入到功能过滤器显示输入被检查两次,过滤器被称为只有一次:

{{getText() | text}} 
相关问题