2015-11-21 17 views
7

Supponiamo che io sono un array di 5000 oggetti (con valori booleani) che devo ng-repeat nel modello:Filtro personalizzato vs funzione di filtro rispetto prestazioni del controller

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

Ora, voglio filtrare questo array ng-repeated sulla base di una variabile dinamica, dite "show_filter", che sto impostando altrove.

Se "show_filter" è impostato su "all", voglio mostrare tutti gli oggetti. Se è impostato su false (il valore booleano), voglio mostrare gli oggetti con la chiave 'value' impostata su false. Lo stesso vale per quando "show_filter" è impostato su true.

Quindi, ci sono due approcci:

1. costruire un filtro personalizzato:

vorrei scrivere un filtro personalizzato per l'attività di filtraggio in questo modo:

filtro:

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' 
     } 
    } 
}) 

modello:

obj in arr | filterArr : show_filter 

2. scrivere una funzione di filtro nel controller:

filtro:

$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' 
    } 
} 

modello:

obj in filterObjects(arr) 

Quale dei due metodi precedenti sarà più veloce? Ho visto il codice filtro personalizzato eseguito ogni volta per ogni ciclo di digest e non solo per le modifiche apportate a $scope.show_filter, il che mi fa pensare che sia piuttosto inefficiente. Anche se non sono sicuro quale sia più veloce tra i due modi.

+0

Hai due funzioni identiche e chiedi quale è il più veloce? Se intendi quale è chiamato il minor numero di volte, allora forse hai già risposto alla tua domanda? – davidkonrad

+0

Non so quante volte viene chiamata la seconda funzione. –

+0

L'alternativa più veloce è quella di esporre un array filtrato a 'ngRepeat'. La seconda funzione deve essere chiamata essere chiamata in ogni ciclo di digestione. L'array – zeroflagL

risposta

4

Entrambe le funzioni verranno chiamate in ogni ciclo di digestione. Questo è piuttosto ovvio per la seconda funzione. Il valore restituito di filterObjects(arr) potrebbe essere diverso per ogni chiamata.

Non è così ovvio perché un filtro venga chiamato in ogni ciclo di digestione. La documentazione riporta quanto segue:

La funzione filtro deve essere una funzione pura, il che significa che deve essere stateless e idempotent. Angolare si basa su queste proprietà ed esegue il filtro solo quando gli input della funzione cambiano.

Quindi, se non arrshow_filter cambiamento, allora il filtro non dovrebbe essere chiamato, giusto? Ma ecco il trucco: rilevare un cambiamento in arr è costoso.

Angolare deve eseguire una copia dell'array per confrontarlo con il contenuto corrente.Anche se nulla è cambiato, ogni singolo oggetto deve essere confrontato. E se gli oggetti sono oggetti, deve essere confrontata ogni singola proprietà di essi. Chiamare direttamente un filtro è invece molto più economico. Ed è quello che fa Angular quando un filtro viene applicato a un array (o oggetto).

Per accelerare l'applicazione avete due scelte. Il primo consiste nel filtrare l'array solo quando è necessario e esporre l'array filtrato a ng-repeat. Per esempio. se è possibile inserire un valore con cui verrà filtrato l'array, filtrare l'array ogni volta che tale valore cambia.

La seconda alternativa può essere utilizzata se la matrice e il filtro non cambiano (quindi non nel tuo caso). Quindi è possibile utilizzare una sola volta vincolante:

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

Questo è utile quando si dispone di un insieme fisso di articoli e desidera ordinare per nome per esempio In questo caso il filtro verrà chiamato una sola volta.

+0

'Chiamare direttamente un filtro è invece molto più economico'. Questo significa il primo approccio o il secondo? Inoltre, una correzione, un filtro non può essere applicato a un oggetto. Nondimeno, grazie per aver chiarito molte cose! –

+0

Si applica al filtro personalizzato (il primo approccio). Un filtro può essere applicato a tutto. Pensa al 'date'filter (una data è un oggetto) o al filtro' json', che ha senso solo per gli oggetti. Un array è anche un oggetto, btw. – zeroflagL

Problemi correlati