Znalazłem kilka implementacji, AuthGuard
które wykorzystują take(1)
. W moim projekcie użyłem first()
.
Czy oba działają w ten sam sposób?
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)
}
}
angular
rxjs
angular2-observables
Karuban
źródło
źródło
first()
itake()
są w ogóle takie same, co myślę, że jest oczywiste, tylko tofirst()
itake(1)
są takie same. Nie jestem pewien z Twojej odpowiedzi, czy uważasz, że nadal istnieje różnica?first()
wyślij powiadomienie o błędzie, podczas gdytake(1)
po prostu nic nie wyemituje.first()
. Jeśli jest to prawidłowy stan aplikacji, wybrałbymtake(1)
..First()
vs.FirstOrDefault()
(i myślę o tym również.Take(1)
w tym, że First wymaga czegoś w kolekcji i daje błąd dla pustej kolekcji -FirstOrDefault()
i.Take(1)
pozwala na to, aby kolekcja była pusta inull
odpowiednioWskazówka: używaj tylko,
first()
jeśli:Jeśli emisje są zerowe i nie obsługujesz ich bezpośrednio (z
catchError
), ten błąd zostanie propagowany, prawdopodobnie spowoduje nieoczekiwany problem w innym miejscu i może być dość trudny do wyśledzenia - zwłaszcza jeśli pochodzi od użytkownika końcowego.W większości przypadków bezpieczniej jest używać,
take(1)
pod warunkiem, że:take(1)
nic emitować, jeśli źródło zakończy się bez emisji.first(x => x > 10)
)Uwaga: Można użyć predykatu z
take(1)
tak:.pipe( filter(x => x > 10), take(1) )
. Nie ma błędu, jeśli nic nie jest większe niż 10.Co powiesz na
single()
Jeśli chcesz być jeszcze bardziej rygorystyczny i nie zezwalać na dwie emisje, możesz użyć
single()
których błędów, jeśli są emisje zerowe lub 2+ . W takim przypadku znowu będziesz musiał obsłużyć błędy.Wskazówka:
Single
czasami może się przydać, jeśli chcesz mieć pewność, że twój obserwowalny łańcuch nie wykonuje dodatkowej pracy, takiej jak dwukrotne wywołanie usługi http i emisja dwóch obserwowalnych. Dodaniesingle
na końcu rury poinformuje Cię, jeśli popełniłeś taki błąd. Używam go w 'module uruchamiającym zadania', w którym przekazujesz obserwowalne zadanie, które powinno emitować tylko jedną wartość, więc przekazuję odpowiedź,single(), catchError()
aby zagwarantować dobre zachowanie.Dlaczego nie zawsze używać
first()
zamiasttake(1)
?znany jako. Jak
first
potencjalnie może powodować więcej błędów?Jeśli masz obiekt obserwowalny, który pobiera coś z usługi, a następnie przesyła go przez kanał, przez
first()
większość czasu powinno być dobrze. Ale jeśli ktoś przyjdzie, aby wyłączyć usługę z jakiegokolwiek powodu - i zmieni ją na emisję,of(null)
alboNEVER
każdy dalszyfirst()
operator zacznie rzucać błędy.Teraz zdaję sobie sprawę, że może to być dokładnie to, czego chcesz - dlatego to tylko wskazówka. Operator
first
zaapelował do mnie, ponieważ brzmiał nieco mniej „niezgrabnie” niż,take(1)
ale trzeba uważać z obsługą błędów, jeśli jest szansa, że źródło nie emituje. Zależy to całkowicie od tego, co robisz.Jeśli masz wartość domyślną (stałą):
Zastanów się również,
.pipe(defaultIfEmpty(42), first())
czy masz wartość domyślną, której należy użyć, jeśli nic nie jest emitowane. To oczywiście nie spowodowałoby błędu, ponieważfirst
zawsze otrzymywałoby wartość.Zauważ, że
defaultIfEmpty
jest wyzwalane tylko wtedy, gdy strumień jest pusty, a nie, jeśli wartość tego, co jest emitowane, wynosinull
.źródło
single
ma więcej różnicfirst
. 1. Emituje tylko wartość oncomplete
. Oznacza to, że jeśli obserwowalne emitują wartość, ale nigdy nie kończą, to single nigdy nie wyemitują wartości. 2. Z jakiegoś powodu, jeśli przekażesz funkcję filtrującą, dosingle
której nic nie pasuje, wyemitujeundefined
wartość, jeśli oryginalna sekwencja nie jest pusta, co nie ma miejsca w przypadkufirst
.Oto trzy obserwabli
A
,B
orazC
ze schematami marmurowe do zbadania różnicy międzyfirst
,take
isingle
operatorzy:* Legenda :
--o--
wartość uzupełnienia----!
błędu----|
Graj z nim na https://thinkrx.io/rxjs/first-vs-take-vs-single/ .
Mając już wszystkie odpowiedzi, chciałem dodać bardziej wizualne wyjaśnienie
Mam nadzieję, że to komuś pomoże
źródło
Jest jedna naprawdę ważna różnica, o której nigdzie nie wspomniano.
take (1) emituje 1, kończy, anuluje subskrypcję
first () emituje 1, kończy, ale nie anuluje subskrypcji.
Oznacza to, że twój obserwowalny element wyjściowy będzie nadal gorący po first (), co prawdopodobnie nie jest oczekiwanym zachowaniem.
UPD: Dotyczy to RxJS 5.2.0. Ten problem może już zostać rozwiązany.
źródło
Wygląda na to, że w RxJS 5.2.0
.first()
operator ma błąd ,Z powodu tego błędu
.take(1)
i.first()
mogą zachowywać się zupełnie inaczej, jeśli używasz ich zswitchMap
:Dzięki
take(1)
temu uzyskasz oczekiwane zachowanie:Ale z
.first()
tobą uzyskasz złe zachowanie:Oto link do codepen
źródło
Okazuje się, że istnieje bardzo ważna różnica między tymi dwiema metodami: first () wyemituje błąd, jeśli strumień zakończy się przed wyemitowaniem wartości. Lub, jeśli podałeś predykat
(i.e. first(value => value === 'foo'))
, wyemituje błąd, jeśli strumień zakończy się przed wyemitowaniem wartości, która przekazuje predykat.Z drugiej strony take (1) będzie z radością kontynuowany, jeśli wartość nigdy nie zostanie wyemitowana ze strumienia. Oto prosty przykład:
Inny przykład, używając predykatu:
Jako nowicjusza w RxJS, to zachowanie było dla mnie bardzo zagmatwane, chociaż było to moja wina, ponieważ poczyniłem nieprawidłowe założenia. Gdybym zadał sobie trud sprawdzania dokumentów, zobaczyłbym, że zachowanie jest wyraźnie udokumentowane :
Powodem, dla którego spotykam się z tym tak często, jest dość powszechny wzorzec Angular 2, w którym obserwowalne są czyszczone ręcznie podczas
OnDestroy
haka cyklu życia:Kod początkowo wygląda nieszkodliwie, ale pojawiają się problemy, gdy komponent, który został wcześniej zniszczony,
stream$
może wyemitować wartość. Ponieważ używamfirst()
, po zniszczeniu składnika jest zgłaszany błąd. Zwykle subskrybuję strumień tylko w celu uzyskania wartości, która ma być używana w składniku, więc nie obchodzi mnie, czy komponent zostanie zniszczony przed emisją strumienia. Z tego powodu zacząłem używaćtake(1)
w prawie wszystkich miejscach, w których wcześniej bym używałfirst()
.filter(fn).take(1)
jest nieco bardziej rozwlekły niżfirst(fn)
, ale w większości przypadków wolę nieco więcej szczegółowości niż obsługa błędów, które ostatecznie nie mają wpływu na aplikację.Warto również zwrócić uwagę: to samo dotyczy
last()
itakeLast(1)
.odniesienie
źródło