web-dev-qa-db-fra.com

Angular 2 observables s'abonner deux fois exécute l'appel deux fois

Problème
Je suis abonné à un httpClient.get observable deux fois. Cependant, cela signifie que mon appel est exécuté deux fois. Pourquoi est-ce?

Preuve
Pour chaque subscribe () que je fais, je reçois une autre ligne dans la page de connexion.

Code (bouton de la page de connexion onSubmit ())

var httpHeaders = new HttpHeaders()
  .append("Authorization", 'Basic ' + btoa(this.username + ':' + this.password));

var observable = this.httpClient.get('api/version/secured', { headers: httpHeaders});
observable.subscribe(
  () => {
    console.log('First request completed');
  },
  (error: HttpErrorResponse) => {
    console.log('First request error');
  }
);
observable.subscribe(
  () => {
    console.log('Second request completed');
  },
  (error: HttpErrorResponse) => {
    console.log('Second request error');
  }
);

Console

zone.js:2935 GET http://localhost:4200/api/version/secured 401 (Unauthorized)
login.component.ts:54 First request error
zone.js:2935 GET http://localhost:4200/api/version/secured 401 (Unauthorized)
login.component.ts:62 First request error

Contexte non pertinent
J'ai un objet LogonService qui gère toutes les fonctionnalités de connexion. Il contient une variable booléenne indiquant si je suis connecté ou non. Chaque fois que j'appelle la fonction de connexion, elle s'abonne à l'observable de httpClient.get pour définir la variable de connexion sur true ou sur false. Mais la fonction de connexion retourne également l'observable, auquel on s'abonne. Il m'a fallu du temps pour lier la double demande à la double souscription. S'il existe un meilleur moyen de suivre l'identifiant que via une variable, faites le moi savoir! J'essaie d'apprendre angulaire :)

7
Rico

Essayez d’utiliser l’opérateur share sur le résultat de HttpClient.get, comme ceci:

var observable = this.httpClient.get('api/version/secured', { headers: httpHeaders })
  .pipe(share());

Vous devez ajouter l'importation suivante au-dessus de votre script:

import { share } from 'rxjs/operators';

L’opérateur share crée une hot observable, c’est-à-dire partagée entre les abonnés. Mais il y a bien plus que cela, je suggérerais cet article de plonger plus profondément (vous pouvez bien sûr aussi google up hot vs cold observables pour trouver plus).

10
Jeto

Votre observable est froid:

Un observable est froid si le producteur de ses notifications est créé chaque fois qu'un observateur souscrit à l'observable. Par exemple, un la minuterie observable est froide; chaque fois qu'un abonnement est fait, un nouveau la minuterie est créée.

Vous devez multicast votre Observable, ou en d'autres termes, pour le rendre chaud:

Un observable est chaud si le producteur de ses notifications ne l’est pas créé chaque fois qu'un observateur s'abonne à l'observable. Pour Par exemple, une observable créée en utilisant fromEvent est hot; l'élément qui produit les événements existe dans le DOM - il n’est pas créé lorsque le fichier l'observateur est abonné.

Pour cela, vous pouvez utiliser share operator, mais il ne peut toujours pas vous garantir un seul appel http. Partager partagera multicast votre observable, ce qui le partagera entre les abonnés, mais une fois l'appel http terminé, il effectuera un nouvel appel http pour les nouveaux abonnés. 

Si vous souhaitez un comportement de mise en cache (effectuer l'appel une fois puis fournir la valeur à chaque abonné chaque fois qu'il s'abonne), vous devez utiliser publishReplay().refCount().

Lectures complémentaires:

Publier et partager des opérateurs

2
meltedspark

Outre les réponses ci-dessus, vous pouvez affecter à observable votre service http, puis vous abonner aux données get. Par exemple:

export class App implements OnInit {

cars$: Observable<Car[]>;

constructor(private carsService: carsService) {

}

ngOnInit() {
    this.lessons$ = this.lessonsService.loadLessons().publishLast().refCount();

    this.lessons$.subscribe(
         () => console.log('lessons loaded'),
         console.error
         );
    }
}

La documentation Angular.

0
StepUp