2017-02-20 57 views
20

Znalazłem kilka implementacji Auth Guards, które używają take(1). W moim projekcie użyłem first(), aby zaspokoić moje potrzeby. Czy to działa tak samo? Albo jeden z nich może mieć zalety.Angular 2 przy użyciu RxJS - take (1) vs first()

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

Odpowiedz

36

Operatorzy first()take() i nie są takie same.

Operator first() pobiera opcjonalny predicate funkcję i emituje error powiadomienie, gdy żadna wartość dopasowane gdy źródło zakończone.

Na przykład ten będzie emitował błąd:

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

... jak ten:

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

ile będzie to zgodne z pierwszą wartość emitowanego:

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

Z drugiej strony take(1) po prostu przyjmuje pierwszą wartość i kończy. Nie ma już żadnej logiki.

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

Następnie z pustym źródło Obserwowalne nie emituje żadnego błędu:

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

Podobnie jak uwaga, nie powiedziałem, że 'pierwszy()' i 'wziąć()' są takie same w ogóle, co moim zdaniem jest oczywiste, że tylko pierwszy '()' i 'take (1)' są takie same. Nie jestem pewien z twojej odpowiedzi, jeśli uważasz, że wciąż istnieje różnica? –

+3

@ GünterZöchbauer Właściwie ich zachowanie jest inne. Jeśli źródło nie emituje niczego i kończy, wówczas 'first()' wysyła powiadomienie o błędzie, podczas gdy 'take (1)' po prostu nie wyśle ​​niczego. – martin

+0

Ok, teraz rozumiem.Wielkie dzięki :) –

3

Jest jedna bardzo ważna różnica, która nie jest nigdzie wspomniane.

odbioru (1) emituje 1, uzupełnia, unsubscribes

pierwszy() emituje 1, uzupełnia, ale nie zrezygnować.

Oznacza to, że twoje obserwowalne zachowanie będzie nadal gorące po pierwszym(), co prawdopodobnie nie jest oczekiwanym zachowaniem.

+0

Nie sądzę, aby jedno z nich anulowało subskrypcję, zobacz http://jsbin.com/nuzulorota/1/edit?js,console. – weltschmerz

+5

Tak, obaj operatorzy wypełniają subskrypcję, różnica występuje w obsłudze błędów. Jeśli to obserwowalne nie wyśle ​​wartości i nadal będzie próbowało pobrać pierwszą wartość za pomocą pierwszego operatora, wygeneruje błąd. Jeśli zastąpimy go operatorem take (1), mimo że nie ma wartości w strumieniu, gdy następuje subskrypcja, nie powoduje to błędu. – noelyahan

4

Wydaje się, że w RxJS 5.2.0 .first() operator ma bug,

powodu tego błędu .take (1) i .first() mogą zachowywać się zupełnie inaczej, jeśli używasz ich z przełącznikiem mapa:

przy odbiorze (1) dostaniesz behviour zgodnie z oczekiwaniami:

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... 

Ale z .first() będzie można dostać złego zachowania:

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... 

Tutaj link do codepen