web-dev-qa-db-fra.com

RxJS - .subscribe () vs .publish (). Connect ()

C'est principalement une question de meilleure pratique/approche RxJs, car mon code POC fonctionne mais je suis tout nouveau pour RxJs.

La question se résume à .subscribe() vs .publish().connect(), car ils semblent tous deux faire la même chose.

Dans mon application angular2, j'ai un bouton qui appelle une fonction pour déconnecter l'utilisateur, qui appelle une fonction dans mon service qui effectue certaines actions côté serveur et me renvoie une URL vers laquelle rediriger l'utilisateur. Afin de lancer la requête, j'appelle .subscribe() pour que l'observable commence à produire des valeurs. Je lisais un article sur "Cold vs Hot Observables" et une autre approche serait d'appeler .publish().connect() au lieu de .subscribe(). Y at-il un avantage à l'une ou l'autre approche.

<a (click)="logout()">Logout</a>

La fonction de déconnexion ressemble à ceci:

logout.component.ts

logout() { this.authService.logout(); }

Et le service (déconnexion réelle) ressemble à ceci:

auth.service.ts

logout() : Observable<boolean>  {
        this.http.get(this.location.prepareExternalUrl('api/v1/authentication/logout'))
            .map(this.extractData)
            .catch(this.handleError)
            .do((x: string) => { window.location.href = x; })
            .subscribe();    // Option A - 

        return Observable.of(true);

    }

auth.service.alternative.ts

logout() : Observable<boolean>  {
        this.http.get(this.location.prepareExternalUrl('api/v1/authentication/logout'))
            .map(this.extractData)
            .catch(this.handleError)
            .do((x: string) => { window.location.href = x; })
            .publish()  // Option B - Make connectable observable
            .connect(); // Option B - Cause the connectable observable to subscribe and produce my value       

        return Observable.of(true);
    }
19
ClaytonK

La différence entre subscribe() et .publish().connect() réside dans le fait qu'ils s'abonnent à sa source Observable. Considérez l'observable suivant:

let source = Observable.from([1, 2, 3])

Cet observable émet toutes les valeurs vers un observateur dès qu'il s'abonne. Donc, si j'ai deux observateurs, ils reçoivent toutes les valeurs dans l'ordre:

source.subscribe(val => console.log('obs1', val));
source.subscribe(val => console.log('obs2', val));

Cela s'imprimera sur la console:

obs1 1
obs1 2
obs1 3
obs2 1
obs2 2
obs2 3

D'un autre côté, l'appel de .publish() renvoie un ConnectableObservable . Cet Observable ne souscrit pas à sa source (source dans notre exemple) dans son constructeur et ne conserve que sa référence. Ensuite, vous pouvez y abonner plusieurs observateurs et rien ne se passe. Enfin, vous appelez connect() et le ConnectableObservable s'abonne au source qui commence à émettre des valeurs. Cette fois, il y a déjà deux observateurs abonnés, il émet donc des valeurs l'un après l'autre:

let connectable = source.publish();
connectable.subscribe(val => console.log('obs1', val));
connectable.subscribe(val => console.log('obs2', val));
connectable.connect();

Quelles impressions à consoler:

obs1 1
obs2 1
obs1 2
obs2 2
obs1 3
obs2 3

Voir la démo en direct: http://plnkr.co/edit/ySWocRr99m1WXwsOGfjS?p=preview

22
martin

Cela contourne un peu votre question mais vous pouvez la trouver utile:

Je ne retournerais pas un flux observable différent de celui qui appelle le service http car cela rend impossible pour la fonction appelante de:

  • annuler le flux
  • modifier le flux
  • déterminer si l'opération a réussi

Au lieu de cela, je ferais:

auth.servive.ts

logout() : Observable<string>  {
       return this.http.get(...).map(this.extractData)          
            .catch(this.handleError);
}

Maintenant, le code appelant peut faire ce qu'il veut avec l'URL résultante

logout.component.ts

logout(){
    this.authService.logout().subscribe(
        url => window.location.href = url,
        err => {
            /*todo: handle if error was thrown by authService.handleError*/
        }
    );
}
4
BeetleJuice