2015-11-21 11 views
7

Angenommen, ich habe ein Array von 5000 Objekten (mit boolean-Werten), die ich ng-repeat in der Vorlage haben:Benutzerdefinierte Filter vs Filterfunktion in der Steuerung Leistungsvergleich

$scope.arr = [ 
    { 
     "value": true 
    }, 
    { 
     "value": false 
    }, 
    { 
     "value": false 
    } 
    //and so on 
] 

Nun, ich möchte dieses ng-repeated Array filtern Auf der Grundlage einer dynamischen Variable, sagen wir "show_filter", die ich woanders setze.

Wenn 'show_filter' auf 'all' gesetzt ist, möchte ich alle Objekte anzeigen. Wenn es auf false gesetzt ist (der boolesche Wert), dann möchte ich Objekte mit dem Schlüssel 'value' zeigen, der auf false gesetzt ist. Das gleiche gilt, wenn 'show_filter' auf 'true' gesetzt ist.

So gibt es zwei Ansätze:

1. Erstellen Sie eine benutzerdefinierte Filter:

Ich würde einen benutzerdefinierten Filter für die Filterung Aufgabe wie folgt schreiben:

Filter:

app.filter('filterArr', function() { 
    return function(arr, show_filter) { 
     var filtered_arr = []; 
     if(show_filter != 'All') { //if show_filter is a boolean value 
      for(var i = 0; i < arr.length; i++) { 
       if(arr[i].value == show_filter) { 
        filtered_arr.push(arr[i]); 
       } 
      } 
      return filtered_arr; 
     } 
     else { 
      return arr; //return the entire array if show_filter is set to 'All' 
     } 
    } 
}) 

Vorlage:

obj in arr | filterArr : show_filter 

2. Schreibe eine Filterfunktion in der Steuerung:

Filter:

$scope.filterObjects = function(arr) { 
    var filtered_arr = []; 
    if($scope.show_filter != 'All') { //if $scope.show_filter is a boolean value 
     for(var i = 0; i < arr.length; i++) { 
      if(arr[i].value == $scope.show_filter) { 
       filtered_arr.push(arr[i]); 
      } 
     } 
     return filtered_arr; 
    } 
    else { 
     return arr; //return the entire array if show_filter is set to 'All' 
    } 
} 

Vorlage:

obj in filterObjects(arr) 

Welche der beiden oben genannten Methoden wird schneller sein? Ich habe gesehen, dass der benutzerdefinierte Filtercode immer für jede Digest-Schleife ausgeführt wird und nicht nur für Änderungen, die an $scope.show_filter vorgenommen werden, was mich glauben lässt, dass es ziemlich ineffizient ist. Obwohl ich nicht sicher bin, was zwischen den beiden Möglichkeiten schneller ist.

+0

Sie haben zwei identische Funktionen und Sie fragen, welche ist am schnellsten? Wenn du meinst, was am wenigsten oft heißt, hast du vielleicht schon deine Frage beantwortet? – davidkonrad

+0

Ich weiß nicht, wie oft die zweite Funktion aufgerufen wird. –

+0

Die schnellste Alternative besteht darin, ein gefiltertes Array mit 'ngRepeat' zu versehen. Die zweite aufgerufene Funktion muss in jedem Digest-Zyklus aufgerufen werden. – zeroflagL

Antwort

4

Beide Funktionen werden in jedem Digest-Zyklus aufgerufen. Das ist für die zweite Funktion offensichtlich. Der Rückgabewert von filterObjects(arr) könnte bei jedem Anruf anders sein. Es ist nicht so offensichtlich, warum ein Filter in jedem Digest-Zyklus aufgerufen würde. Die Dokumentation besagt folgendes:

Die Filterfunktion sollte eine reine Funktion sein, was bedeutet, dass sie zustandslos und idempotent sein sollte. Angular stützt sich auf diese Eigenschaften und führt den Filter nur dann aus, wenn sich die Eingaben für die Funktion ändern.

Also, wenn weder arr noch show_filter Änderung dann die Filter nicht aufgerufen werden sollen, nicht wahr? Aber hier ist der Haken: Eine Änderung in arr zu erkennen ist teuer.

Angular muss eine Kopie des Arrays erstellen, um es mit dem aktuellen Inhalt zu vergleichen.Auch wenn sich nichts geändert hat, muss jeder einzelne Artikel verglichen werden. Und wenn die Gegenstände Objekte sind, muss jede einzelne Eigenschaft von ihnen verglichen werden. Direkter Aufruf eines Filters ist viel billiger. Und genau das tut Angular, wenn ein Filter auf ein Array (oder Objekt) angewendet wird.

Um die Anwendung zu beschleunigen, haben Sie zwei Möglichkeiten. Die erste besteht darin, das Array nur bei Bedarf zu filtern und das gefilterte Array ng-repeat zur Verfügung zu stellen. Z.B. Wenn Sie einen Wert eingeben können, nach dem das Array gefiltert wird, filtern Sie das Array, wenn sich dieser Wert ändert.

Die zweite Alternative kann verwendet werden, wenn sich sowohl das Array als auch der Filter nicht ändern (also nicht in Ihrem Fall). Dann können Sie einmalige Bindung verwenden:

<li ng-repeat="item in ::array | filter"> 

, die nützlich ist, wenn Sie einen festen Satz von Elementen haben und wollen, dass sie zum Beispiel nach Namen sortieren Der Filter wird in diesem Fall nur einmal aufgerufen.

+0

"Ein Filter direkt aufrufen ist viel billiger". Bedeutet dies die erste Annäherung oder Sekunde? Auch eine Korrektur, ein Filter kann nicht auf ein Objekt angewendet werden. Trotzdem, vielen Dank für die Klärung! –

+0

Dies gilt für den benutzerdefinierten Filter (der erste Ansatz). Ein Filter kann auf alles angewendet werden. Denken Sie an den "date" -Filter (ein Datum ist ein Objekt) oder den "json" -Filter, der nur für Objekte Sinn macht. Ein Array ist auch ein Objekt, übrigens. – zeroflagL

Verwandte Themen