Eu encontrei algumas implementações de AuthGuard
s que usam take(1)
. No meu projeto, eu usei first()
.
Os dois funcionam da mesma maneira?
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
fonte
fonte
first()
etake()
é o mesmo em geral, o que acho óbvio, apenas issofirst()
etake(1)
é o mesmo. Não tenho certeza da sua resposta se você acha que ainda há uma diferença?first()
envie uma notificação de erro enquantotake(1)
simplesmente não emitirá nada.first()
. Se for um estado de aplicativo válido, eu aceitariatake(1)
..First()
vs do .NET.FirstOrDefault()
(e pense nisso também.Take(1)
, porque o First requer algo na coleção e gera um erro para uma coleção vazia - e ambos,FirstOrDefault()
e.Take(1)
permite que a coleção fique vazia e retornenull
e esvazie a coleção, respectivamente.Dica: use apenas
first()
se:Se houver zero emissões e você não estiver lidando com isso explicitamente (com
catchError
), esse erro será propagado, possivelmente causará um problema inesperado em outro lugar e poderá ser bastante difícil de rastrear - especialmente se for de um usuário final.Você está mais seguro usando
take(1)
a maior parte, desde que:take(1)
não pode emitir nada se a fonte for concluída sem emissão.first(x => x > 10)
)Nota: Você pode usar um predicado com
take(1)
como este:.pipe( filter(x => x > 10), take(1) )
. Não há erro com isso se nada for maior que 10.A respeito
single()
Se você quiser ser ainda mais rigoroso e não permitir duas emissões, poderá usar
single()
quais erros se houver zero ou mais de duas emissões . Novamente, você precisaria lidar com erros nesse caso.Dica:
Single
ocasionalmente pode ser útil se você quiser garantir que sua cadeia observável não esteja fazendo um trabalho extra, como chamar um serviço http duas vezes e emitir dois observáveis. Adicionarsingle
ao final do tubo o informará se você cometeu esse erro. Estou usando-o em um 'corredor de tarefas', onde você passa uma tarefa observável que deve emitir apenas um valor; portanto, passo a respostasingle(), catchError()
para garantir um bom comportamento.Por que nem sempre usar em
first()
vez detake(1)
?aka. Como
first
potencialmente pode causar mais erros?Se você tem um observável que retira algo de um serviço e o canaliza,
first()
deve ficar bem a maior parte do tempo. Mas se alguém vier desativar o serviço por qualquer motivo - e alterá-lo para emitirof(null)
ouNEVER
então quaisquerfirst()
operadores a jusante começarão a gerar erros.Agora eu percebo que pode ser exatamente o que você deseja - daí o motivo de esta ser apenas uma dica. O operador
first
me atraiu porque parecia um pouco menos desajeitado do que,take(1)
mas você precisa ter cuidado ao lidar com erros, se houver uma chance de a fonte não emitir. Depende inteiramente do que você está fazendo.Se você tiver um valor padrão (constante):
Considere também
.pipe(defaultIfEmpty(42), first())
se você tem um valor padrão que deve ser usado se nada for emitido. Obviamente, isso não geraria um erro, porquefirst
sempre receberia um valor.Observe que isso
defaultIfEmpty
é acionado apenas se o fluxo estiver vazio, não se o valor do que for emitido fornull
.fonte
single
há mais diferençasfirst
. 1. Ele emitirá apenas o valor ativadocomplete
. Isso significa que se o observável emitir um valor, mas nunca for concluído, o single nunca emitirá um valor. 2. Por algum motivo, se você passar uma função de filtro para asingle
qual não corresponda a nada, ela emitirá umundefined
valor se a sequência original não estiver vazia, o que não é o casofirst
.Aqui estão três observáveis
A
,B
eC
com diagramas de mármore para explorar a diferença entrefirst
,take
esingle
operadores:* Legenda : conclusão do erro de
--o--
valor----!
----|
Brinque com ele em https://thinkrx.io/rxjs/first-vs-take-vs-single/ .
Já tendo todas as respostas, queria adicionar uma explicação mais visual
Espero que ajude alguém
fonte
Há uma diferença realmente importante que não é mencionada em nenhum lugar.
take (1) emite 1, conclui, cancela a inscrição
first () emite 1, é concluído, mas não cancela a inscrição.
Isso significa que seu observável upstream ainda estará quente após first (), o que provavelmente não é um comportamento esperado.
UPD: Refere-se ao RxJS 5.2.0. Esse problema já pode estar corrigido.
fonte
Parece que no RxJS 5.2.0 o
.first()
operador tem um bug ,Por causa desse bug
.take(1)
e.first()
pode se comportar bem diferente se você os estiver usando comswitchMap
:Com
take(1)
você obterá o comportamento conforme o esperado:Mas com
.first()
você terá um comportamento errado:Aqui está um link para codepen
fonte