J'ai trouvé quelques implémentations de AuthGuard
s qui utilisent take(1)
. Dans mon projet, j'ai utilisé first()
.
Les deux fonctionnent-ils de la même manière?
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
la source
la source
first()
ettake()
sont les mêmes en général, ce qui je pense est évident, seulement celafirst()
ettake(1)
sont les mêmes. Je ne suis pas sûr d'après votre réponse si vous pensez qu'il y a encore une différence?first()
envoyez une notification d'erreur alorstake(1)
qu'elle n'émettra tout simplement rien.first()
. Si c'est un état d'application valide, j'irais avectake(1)
..First()
vs de .NET.FirstOrDefault()
(et en vient à y penser aussi.Take(1)
en ce que First nécessite quelque chose dans la collection et donne une erreur pour une collection vide - et les deuxFirstOrDefault()
et.Take(1)
autorise la collection à être vide et retournenull
et une collection vide respectivement.Astuce: à n'utiliser que
first()
si:S'il n'y a aucune émission et que vous ne la gérez pas explicitement (avec
catchError
), cette erreur se propagera, causera peut-être un problème inattendu ailleurs et peut être assez difficile à localiser - surtout si elle provient d'un utilisateur final.Vous êtes plus sûr d'utiliser
take(1)
la plupart du temps à condition que:take(1)
ne rien émettre si la source se termine sans émission.first(x => x > 10)
)Remarque: Vous pouvez utiliser un prédicat
take(1)
comme ceci:.pipe( filter(x => x > 10), take(1) )
. Il n'y a pas d'erreur avec ceci si rien n'est jamais supérieur à 10.Qu'en est-il de
single()
Si vous voulez être encore plus strict et interdire deux émissions, vous pouvez utiliser
single()
quelles erreurs s'il y a zéro ou 2+ émissions . Encore une fois, vous devrez gérer les erreurs dans ce cas.Astuce:
Single
peut parfois être utile si vous voulez vous assurer que votre chaîne observable ne fait pas de travail supplémentaire, comme appeler un service http deux fois et émettre deux observables. Ajoutersingle
à la fin du tuyau vous permettra de savoir si vous avez fait une telle erreur. Je l'utilise dans un 'task runner' où vous passez une tâche observable qui ne devrait émettre qu'une seule valeur, donc je transmets la réponsesingle(), catchError()
pour garantir un bon comportement.Pourquoi ne pas toujours utiliser à la
first()
place detake(1)
?alias. Comment peut
first
potentiellement causer plus d'erreurs?Si vous avez un observable qui prend quelque chose d'un service et qui le transite ensuite,
first()
vous devriez être en ordre la plupart du temps. Mais si quelqu'un vient désactiver le service pour une raison quelconque - et le change pour émettreof(null)
ouNEVER
alors toutfirst()
opérateur en aval commencerait à lancer des erreurs.Maintenant, je réalise que c'est peut-être exactement ce que vous voulez - d'où la raison pour laquelle ce n'est qu'un conseil. L'opérateur
first
m'a séduit parce que cela semblait un peu moins `` maladroit '' que,take(1)
mais vous devez faire attention à la gestion des erreurs s'il y a un risque que la source n'émette pas. Cela dépendra entièrement de ce que vous faites.Si vous avez une valeur par défaut (constante):
Considérez également
.pipe(defaultIfEmpty(42), first())
si vous avez une valeur par défaut qui devrait être utilisée si rien n'est émis. Cela ne soulèverait bien sûr pas une erreur carfirst
recevrait toujours une valeur.Notez que cela
defaultIfEmpty
n'est déclenché que si le flux est vide, pas si la valeur de ce qui est émis estnull
.la source
single
a plus de différences avecfirst
. 1. Il n'émettra la valeur que surcomplete
. Cela signifie que si l'observable émet une valeur mais ne se termine jamais, alors single n'émettra jamais de valeur. 2. Pour une raison quelconque, si vous transmettez une fonction de filtre àsingle
laquelle ne correspond rien, elle émettra uneundefined
valeur si la séquence d'origine n'est pas vide, ce qui n'est pas le cas avecfirst
.Voici trois Observables
A
,B
etC
avec des schémas de marbre pour explorer la différence entrefirst
,take
et lessingle
opérateurs:* Légende : achèvement de l' erreur de
--o--
valeur----!
----|
Jouez avec sur https://thinkrx.io/rxjs/first-vs-take-vs-single/ .
Ayant déjà toutes les réponses, je voulais ajouter une explication plus visuelle
J'espère que ça aide quelqu'un
la source
Il y a une différence vraiment importante qui n'est mentionnée nulle part.
take (1) émet 1, termine, se désabonne
first () émet 1, se termine, mais ne se désabonne pas.
Cela signifie que votre observable en amont sera toujours chaud après first (), ce qui n'est probablement pas un comportement attendu.
UPD: Cela fait référence à RxJS 5.2.0. Ce problème est peut-être déjà résolu.
la source
Il semble que dans RxJS 5.2.0 l'
.first()
opérateur ait un bogue ,À cause de ce bug
.take(1)
et.first()
peuvent se comporter très différemment si vous les utilisez avecswitchMap
:Avec
take(1)
vous obtiendrez un comportement comme prévu:Mais avec
.first()
vous, vous obtiendrez un mauvais comportement:Voici un lien vers codepen
la source