1000 votes

BehaviorSubject vs Observable ?

Je me penche sur les modèles Angular RxJs et je ne comprends pas la différence entre une BehaviorSubject et un Observable .

D'après ce que j'ai compris, un BehaviorSubject est une valeur qui peut évoluer dans le temps (on peut s'y abonner et les abonnés peuvent recevoir des résultats actualisés). Il semble que ce soit exactement le même objectif que celui d'un objet de type Observable .

Quand utiliseriez-vous un Observable contre a BehaviorSubject ? Y a-t-il des avantages à utiliser un BehaviorSubject sur un Observable ou vice versa ?

4 votes

Cet article m'a particulièrement aidé à comprendre les observables vs les sujets vs les sujets de comportement à la manière d'ELI5. javascript.plainenglish.io/

1376voto

Shantanu Bhadoria Points 6774

ComportementSujet est un type de sujet, un sujet est un type spécial d'observable, de sorte que vous pouvez vous abonner aux messages comme n'importe quel autre observable. Les caractéristiques uniques de BehaviorSubject sont :

  • Il a besoin d'une valeur initiale car il doit toujours renvoyer une valeur lors de la souscription, même s'il n'a pas reçu d'appel. next()
  • Lors de l'abonnement, il renvoie la dernière valeur du sujet. Une observable régulière ne se déclenche que lorsqu'elle reçoit un message de type onnext
  • à n'importe quel moment, vous pouvez récupérer la dernière valeur du sujet dans un code non observable en utilisant la fonction getValue() méthode.

Les caractéristiques uniques d'un sujet par rapport à un observable sont les suivantes :

  • C'est un observateur en plus d'être un observable, donc vous pouvez également envoyer des valeurs à un sujet en plus de vous y abonner.

En outre, vous pouvez obtenir un observable à partir du sujet du comportement en utilisant la fonction asObservable() méthode sur BehaviorSubject .

Observable est un Générique, et BehaviorSubject est techniquement un sous-type d'Observable car BehaviorSubject est un observable avec des qualités spécifiques.

Exemple avec ComportementSujet :

// Behavior Subject

// a is an initial value. if there is a subscription 
// after this, it would get "a" value immediately
let bSubject = new BehaviorSubject("a"); 

bSubject.next("b");

bSubject.subscribe(value => {
  console.log("Subscription got", value); // Subscription got b, 
                                          // ^ This would not happen 
                                          // for a generic observable 
                                          // or generic subject by default
});

bSubject.next("c"); // Subscription got c
bSubject.next("d"); // Subscription got d

Exemple 2 avec un sujet régulier :

// Regular Subject

let subject = new Subject(); 

subject.next("b");

subject.subscribe(value => {
  console.log("Subscription got", value); // Subscription wont get 
                                          // anything at this point
});

subject.next("c"); // Subscription got c
subject.next("d"); // Subscription got d

Une observable peut être créée à partir des deux Subject et BehaviorSubject en utilisant subject.asObservable() .

La seule différence est que vous ne pouvez pas envoyer de valeurs à un observable en utilisant la fonction next() méthode.

Dans les services Angular, j'utiliserais BehaviorSubject pour un service de données, car un service angulaire s'initialise souvent avant le composant et le sujet du comportement garantit que le composant consommant le service reçoit les dernières données mises à jour, même s'il n'y a pas de nouvelles mises à jour depuis l'abonnement du composant à ces données.

22 votes

Je suis un peu confus avec l'exemple 2 du sujet régulier. Pourquoi l'abonnement ne reçoit-il rien alors qu'à la deuxième ligne, vous envoyez des valeurs au sujet en utilisant subject.next("b") ?

59 votes

@jmod999 Le deuxième exemple est un sujet régulier qui reçoit une valeur juste avant l'appel de l'abonnement. Dans les sujets ordinaires, l'abonnement n'est déclenché que pour les valeurs reçues après l'appel de l'abonnement. Puisque a est reçu juste avant l'abonnement, il n'est pas envoyé à l'abonnement.

0 votes

Une remarque à propos de cette solution fantastique, si vous l'utilisez dans une fonction et la renvoyez, alors renvoyez un observable. J'ai eu des problèmes avec le retour d'un sujet, et cela perturbe les autres développeurs qui ne savent que ce que sont les Observables.

270voto

Vamshi Points 5473

Observable : Résultat différent pour chaque Observable

Une différence très très importante. Puisque l'Observable est juste une fonction, il n'a pas d'état, donc pour chaque nouvel Observable, il exécute le code de création de l'Observable encore et encore. Il en résulte que :

Le code est exécuté pour chaque observateur . Si c'est un appel HTTP, il est appelé pour chaque observateur.

Cela provoque des bogues et des inefficacités majeures.

BehaviorSubject (ou Subject ) stocke les détails des observateurs, exécute le code une seule fois et donne le résultat à tous les observateurs .

Ex :

JSBin : http://jsbin.com/qowulet/edit?js,console

// --- Observable ---
let randomNumGenerator1 = Rx.Observable.create(observer => {
   observer.next(Math.random());
});

let observer1 = randomNumGenerator1
      .subscribe(num => console.log('observer 1: '+ num));

let observer2 = randomNumGenerator1
      .subscribe(num => console.log('observer 2: '+ num));

// ------ BehaviorSubject/ Subject

let randomNumGenerator2 = new Rx.BehaviorSubject(0);
randomNumGenerator2.next(Math.random());

let observer1Subject = randomNumGenerator2
      .subscribe(num=> console.log('observer subject 1: '+ num));

let observer2Subject = randomNumGenerator2
      .subscribe(num=> console.log('observer subject 2: '+ num));

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.3/Rx.min.js"></script>

Sortie :

"observer 1: 0.7184075243594013"
"observer 2: 0.41271850211336103"
"observer subject 1: 0.8034263165479893"
"observer subject 2: 0.8034263165479893"

Observez comment l'utilisation de Observable.create a créé une sortie différente pour chaque observateur, mais BehaviorSubject a donné le même résultat pour tous les observateurs. Ceci est important.


Autres différences résumées.

         Observable                       BehaviorSubject/Subject               

 Is just a function, no state         Has state. Stores data in memory    

 Code run for each observer           Same code run                       
                                      only once for all observers         

 Creates only Observable             Can create and also listen Observable
 ( data producer alone )              ( data producer and consumer )      

 Usage: Simple Observable with only   Usage:                              
 one Obeserver.                       * Store data and modify frequently  
                                      * Multiple observers listen to data 
                                      * Proxy between Observable  and     
                                        Observer

3 votes

Toute personne venant de KnockoutJS's ko.observable() verra immédiatement plus de parallèles avec Rx.BehaviorSubject par rapport à Rx.Observable

0 votes

@Skeptor Observable : La méthode subscribe déclenchera toujours la méthode onNext associée à l'observateur et apportera la valeur de retour. ComportementSujet/sujet : La méthode subcribe avec le sujet ne déclenchera pas la méthode onNext de son observateur jusqu'à ce qu'elle trouve la dernière valeur dans le flux.

35voto

Md Ayub Ali Sarker Points 3473

L'objet Observable représente une collection basée sur le push.

Les interfaces Observer et Observable fournissent un mécanisme généralisé de notification par poussée, également connu sous le nom de modèle de conception d'observateur. L'objet Observable représente l'objet qui envoie les notifications (le fournisseur) ; l'objet Observer représente la classe qui les reçoit (l'observateur).

La classe Subject hérite à la fois d'Observable et d'Observer, en ce sens qu'elle est à la fois un observateur et un observable. Vous pouvez utiliser un sujet pour abonner tous les observateurs, puis abonner le sujet à une source de données dorsale.

var subject = new Rx.Subject();

var subscription = subject.subscribe(
    function (x) { console.log('onNext: ' + x); },
    function (e) { console.log('onError: ' + e.message); },
    function () { console.log('onCompleted'); });

subject.onNext(1);
// => onNext: 1

subject.onNext(2);
// => onNext: 2

subject.onCompleted();
// => onCompleted

subscription.dispose();

En savoir plus https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/subjects.md

0 votes

Quelle est la différence entre subscription.dispose() et subscription.unsubscribe() ?

4 votes

@choopage aucune différence. le dernier est la nouvelle voie

0 votes

Doit se désabonner avant que le sujet ne soit éliminé, sinon, l'abonnement devient un garbage puisqu'il s'abonne à une valeur nulle.

22voto

Ce que je ne vois pas dans les exemples, c'est que lorsque vous transformez BehaviorSubject en Observable via asObservable, il hérite du comportement consistant à renvoyer la dernière valeur lors de la souscription.

C'est la partie la plus délicate, car souvent les bibliothèques exposent les champs comme observables (par exemple, les paramètres dans ActivatedRoute dans Angular2), mais peuvent utiliser Subject ou BehaviorSubject dans les coulisses. Ce qu'elles utilisent peut affecter le comportement de l'abonnement.

Voir ici http://jsbin.com/ziquxapubo/edit?html,js,console

let A = new Rx.Subject();
let B = new Rx.BehaviorSubject(0);

A.next(1);
B.next(1);

A.asObservable().subscribe(n => console.log('A', n));
B.asObservable().subscribe(n => console.log('B', n));

A.next(2);
B.next(2);

17voto

student Points 87

Un site observable vous permet de vous abonner uniquement alors qu'un sujet vous permet à la fois de publier et de vous abonner.

Donc un sujet permet à votre services pour être utilisé à la fois comme éditeur et comme abonné.

Pour l'instant, je ne suis pas très doué pour Observable Je ne partagerai donc qu'un exemple de Subject .

Comprenons mieux avec un CLI Angular exemple. Exécutez les commandes suivantes :

npm install -g @angular/cli

ng new angular2-subject

cd angular2-subject

ng serve

Remplacer le contenu de app.component.html avec :

<div *ngIf="message">
  {{message}}
</div>

<app-home>
</app-home>

Exécutez la commande ng g c components/home pour générer le composant domestique. Remplacez le contenu de home.component.html avec :

<input type="text" placeholder="Enter message" #message>
<button type="button" (click)="setMessage(message)" >Send message</button>

#message est la variable locale ici. Ajouter une propriété message: string; à la app.component.ts de la classe.

Exécutez cette commande ng g s service/message . Cela va générer un service à src\app\service\message.service.ts . Fournir ce service à l'application .

Importation Subject en MessageService . Ajoutez également un sujet. Le code final ressemblera à ceci :

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class MessageService {

  public message = new Subject<string>();

  setMessage(value: string) {
    this.message.next(value); //it is publishing this value to all the subscribers that have already subscribed to this message
  }
}

Maintenant, injectez ce service dans home.component.ts et passer une instance de celui-ci au constructeur. Faites ceci pour app.component.ts aussi. Utilisez cette instance de service pour transmettre la valeur de #message à la fonction de service setMessage :

import { Component } from '@angular/core';
import { MessageService } from '../../service/message.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent {

  constructor(public messageService:MessageService) { }

  setMessage(event) {
    console.log(event.value);
    this.messageService.setMessage(event.value);
  }
}

À l'intérieur de app.component.ts pour s'abonner et se désabonner (afin d'éviter les fuites de mémoire) à l'outil de gestion de l'information. Subject :

import { Component, OnDestroy } from '@angular/core';
import { MessageService } from './service/message.service';
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {

  message: string;
  subscription: Subscription;

  constructor(public messageService: MessageService) { }

  ngOnInit() {
    this.subscription = this.messageService.message.subscribe(
      (message) => {
        this.message = message;
      }
    );
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

C'est tout.

Maintenant, toute valeur saisie dans #message de home.component.html sont imprimés à {{message}} à l'intérieur de app.component.html

0 votes

Pourquoi cette image géante ? Si elle n'est pas directement liée à votre réponse, cela ressemble à du votebait.

0 votes

@ruffin C'est juste une réponse moyenne avec un nombre moyen de votes, regardez mon profil. Pas vraiment du votebait :D

2 votes

Je vous ai donné un vote positif plus tôt, mais vous avez esquivé la question de savoir pourquoi l'image est là. Ce n'est pas directement lié à votre réponse. Peu importe que vous ayez beaucoup de points ou pas Si l'image n'est pas directement et spécifiquement explicative, je vous demande de la retirer. . /hausser les épaules

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X