2017-03-10 5 views
4

betrachte das folgende Beispiel:Warum läuft der AngularJS-Filter nur einmal?

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>

bemerken, dass die Funktion getText() zweimal ausgeführt wird, während der Filter nur einmal ausgeführt wird. Ich nehme an, dass die getText() Funktion zweimal ausgeführt wird, um sicherzustellen, dass das Modell jetzt stabil ist. Warum nicht das gleiche Verhalten für den Filter?

Antwort

5

Die Dokumentation ist ziemlich klar zu diesem Thema:

In einer Vorlage werden Filter nur dann ausgeführt, wenn ihre Eingänge geändert haben. Dies ist leistungsfähiger als das Ausführen eines Filters für jeden $ Digest, wie es bei Ausdrücken der Fall ist.

Here's the source.

1

Wenn ein Ausdruck in einer Vorlage verwendet wird, dann AngularJS wertet zunächst das Material/Text in Klammern (Interpolation) und wandelt dann den Wert/Ausgabe-String und dann diesen String-Wertes in den Einsatz HTML-Element/-Attribut

From AngularJS Docs:- In Vorlagen werden Filter nur ausgeführt, wenn sich ihre Eingaben geändert haben. Dies ist leistungsfähiger als das Ausführen eines Filters für jeden $ Digest, wie es bei Ausdrücken der Fall ist.

Es gibt zwei Ausnahmen von dieser Regel:

  • In der Regel ist dies nur auf Filter angewandt wird, die primitiven Werte als Eingänge nehmen. Filter, die Objekte als Eingabe empfangen, werden auf jedem $ digest ausgeführt, da es zu kostspielig wäre, nachzuverfolgen, ob die Eingaben geändert haben.
  • Filter, die als $ stateful markiert sind, werden auch für jeden $ digest ausgeführt. Weitere Informationen finden Sie unter Stateful-Filter. Beachten Sie, dass keine AngularJS-Kernfilter $ stateful sind.
0

Per documentation,

Filter werden nur dann, wenn ihre Eingaben geändert haben ausgeführt. Dies ist leistungsfähiger als das Ausführen eines Filters auf jedem $digest, wie es bei Ausdrücken der Fall ist.

Es gibt zwei Ausnahmen von dieser Regel:

In der Regel ist dies nur auf Filter angewendet wird, die Grundwerte als Eingaben nehmen. Filter, die Objekte als Eingabe empfangen, werden auf jedem $digest ausgeführt, da es zu kostspielig wäre, nachzuverfolgen, ob sich die Eingänge geändert haben.

Filter, die als $stateful markiert sind, werden auch auf jedem $digest ausgeführt. Weitere Informationen finden Sie unter Stateful-Filter. Beachten Sie, dass keine AngularJS-Kernfilter $stateful sind.

Da Sie einen primitiven Wert haben, der sich nicht ändert, muss der Filter nicht erneut ausgeführt werden.Ändern Sie den leeren String '' zu einem Objektliteral {} und sehen, was passiert;)

3

Cosmin ist genau richtig - und hier ist ein Demo, es zu beweisen (die zufälligerweise einen Stack-Überlauf an einem gewissen Punkt verursachen) - wenn getText () aufgerufen wird, weist er dem Eingang des Textfilters einen neuen Wert zu, wodurch dieser erneut ausgewertet wird, was einen anderen Digest-Zyklus verursacht, der dazu führt, dass der Filter neu bewertet wird ... was schließlich zu einem Stapelüberlauf führt.


EDIT entfernt ich einen Testabschnitt, der den Überlauf verursacht wurde - dies nur der Filter bewerten zweimal haben wird, da getText nur zweimal aufgerufen wird.

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

Beide Bindungen zweimal überprüft werden, aber man kann nur sehen, ein zweimal überprüft. Im Fall des Filters ist die Eingabe ''. Angular prüft nur den INPUT (source) auf den Filter, wenn die Prüfung schmutzig ist, und überprüft es zweimal und vergleicht die Ergebnisse. Also ruft es den Filter nicht zweimal auf.

Für die geschweifte Klammerbindung wird das RESULT des Ausdrucks zweimal überprüft, und Sie können somit sehen, dass Ihre Funktion zweimal aufgerufen wird.

Aber wenn Sie die Eingabe in den Filter eine Funktion wie this machen, werden Sie sehen, dass es zweimal genau wie Ihre geschweifte Klammerbindung aufgerufen wird und der Filter immer noch nur einmal aufgerufen wird.

den Filtereingang zu einer Funktion ändern zeigt, dass die Eingabe zweimal geprüft und Filter werden nur einmal genannt:

{{getText() | text}}