2017-02-20 4 views
20

Ich fand einige Implementierung von Auth Guards, die take(1) verwendet. Auf meinem Projekt habe ich first() verwendet, um meine Bedürfnisse zu befriedigen. Funktioniert es genauso? Oder einer von ihnen könnte Vorteile oder so haben.Angular 2 mit RxJS - Take (1) vs ersten()

import 'rxjs/add/operator/map'; 
import 'rxjs/add/operator/first'; 
import { Observable } from 'rxjs/Observable'; 

import { Injectable } from '@angular/core'; 
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; 
import { AngularFire } from 'angularfire2'; 

@Injectable() 
export class AuthGuard implements CanActivate { 

    constructor(private angularFire: AngularFire, private router: Router) { } 

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean { 
     return this.angularFire.auth.map(
      (auth) => { 
       if (auth) { 
        this.router.navigate(['/dashboard']); 
        return false; 
       } else { 
        return true; 
       } 
      } 
     ).first(); // Just change this to .take(1) 
    } 
} 

Antwort

36

Operatoren first() und take() sind nicht das gleiche.

first() Der Bediener nimmt eine optionale Funktion predicate und emittiert eine error Benachrichtigung, wenn kein Wert abgeglichen, wenn die Quelle abgeschlossen.

Beispiel dies einen Fehler emittieren:

Rx.Observable.empty() 
    .first() 
    .subscribe(
    val => console.log(val), 
    err => console.log('Error', err) 
); 

... sowie das:

Rx.Observable.range(1, 5) 
    .first(val => val > 6) 
    .subscribe(
    val => console.log(val), 
    err => console.log('Error', err) 
); 

Während dies entspricht den ersten Wert emittieren:

Rx.Observable.range(1, 5) 
    .first() 
    .subscribe(
    val => console.log(val), 
    err => console.log('Error', err) 
); 

Auf der anderen Seite take(1) nimmt nur den ersten Wert und schließt ab. Keine weitere Logik ist beteiligt.

Rx.Observable.range(1, 5) 
    .take(1) 
    .subscribe(
    val => console.log(val), 
    err => console.log('Error', err) 
); 

Dann mit leerer Quelle beobachtbare es keine Störungen aussendet:

Rx.Observable.empty() 
    .take(1) 
    .subscribe(
    val => console.log(val), 
    err => console.log('Error', err) 
); 
+0

Wie Anmerkung, ich habe nicht gesagt, dass 'first()' und 'nehmen()' im Allgemeinen gleich sind, was ich denke, liegt auf der Hand, nur dass 'erstes()' und 'take (1)' sind gleich. Ich bin mir nicht sicher aus Ihrer Antwort, wenn Sie denken, dass es noch einen Unterschied gibt? –

+3

@ GünterZöchbauer Eigentlich ist ihr Verhalten anders. Wenn die Quelle nichts ausgibt und dann 'first()' sendet, wird eine Fehlermeldung gesendet, während 'take (1)' einfach nichts ausgibt. – martin

+0

Ok, jetzt verstehe ich.Vielen Dank :) –

3

Es gibt einen wirklich wichtigen Unterschied, der nicht überall erwähnt wird.

nehmen (1) emittiert 1 vervollständigt, das Abo kündigt

erste() emittiert 1, abgeschlossen ist, aber nicht abmelden.

Es bedeutet, dass Ihre Upstream-Observable immer noch heiß nach dem ersten() sein wird, was wahrscheinlich kein erwartetes Verhalten ist.

+0

Ich glaube nicht, dass sich beide abmelden, siehe http://jsbin.com/nuzulorota/1/edit?js,console. – weltschmerz

+5

Ja, beide Betreiber vervollständigen das Abonnement, der Unterschied liegt in der Fehlerbehandlung. Wenn dieses Observable keine Werte ausgibt und trotzdem versucht, den ersten Wert mit dem ersten Operator zu ermitteln, wird ein Fehler ausgegeben. Wenn wir es durch den Take (1) -Operator ersetzen, obwohl kein Wert im Stream vorhanden ist, wenn die Subskription stattfindet, wird kein Fehler ausgegeben. – noelyahan

4

Es scheint, dass in RxJS .First 5.2.0 Operator() a hat bug,

Aufgrund dieser Fehler .take (1) und .First() ganz anders verhalten können, wenn man sie mit Schalter verwenden Karte:

mit Take (1) Sie erhalten GERÄTEVERHALTEN wie erwartet:

var x = Rx.Observable.interval(1000) 
    .do(x=> console.log("One")) 
    .take(1) 
    .switchMap(x => Rx.Observable.interval(1000)) 
    .do(x=> console.log("Two")) 
    .subscribe((x) => {}) 

// In console you will see: 
// One 
// Two 
// Two 
// Two 
// Two 
// etc... 

Aber mit .First() Sie falsches Verhalten erhalten:

var x = Rx.Observable.interval(1000) 
    .do(x=> console.log("One")) 
    .first() 
    .switchMap(x => Rx.Observable.interval(1000)) 
    .do(x=> console.log("Two")) 
    .subscribe((x) => {}) 

// In console you will see: 
// One 
// One 
// Two 
// One 
// Two 
// One 
// etc... 

Hier verlinken auf codepen