web-dev-qa-db-fra.com

BehaviorSubject vs Observable?

Je cherche dans les modèles Angular _ RxJs et je ne comprends pas la différence entre un BehaviorSubject et un Observable.

De mon point de vue, un BehaviorSubject est une valeur qui peut changer au fil du temps (il est possible de s’abonner à un abonnement et les abonnés peuvent recevoir des résultats mis à jour). Cela semble être exactement le même but d'un Observable.

Quand utiliseriez-vous un Observable contre un BehaviorSubject? Y a-t-il des avantages à utiliser une BehaviorSubject par rapport à une Observable ou inversement?

539
Kevin Mark

BehaviorSubject est un type de sujet, un sujet est un type spécial d'observable afin que vous puissiez vous abonner à des messages comme n'importe quel autre observable. Les caractéristiques uniques de BehaviorSubject sont les suivantes:

  • 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 de next().
  • Lors de la souscription, il retourne la dernière valeur du sujet. Une observable régulière ne se déclenche que lorsqu'elle reçoit un onnext
  • à tout moment, vous pouvez récupérer la dernière valeur du sujet dans un code non observable à l'aide de la méthode getValue().

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

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

De plus, vous pouvez obtenir une observation du comportement du sujet à l’aide de la méthode asObservable() de BehaviorSubject.

Observable est un générique et BehaviorSubject est techniquement un sous-type d’observable, car BehaviorSubject est un observable doté de qualités spécifiques.

Exemple avec BehaviorSubject:

// 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 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 de Subject et BehaviorSubject à l'aide de subject.asObservable().

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

Dans Angular services, j’utiliserais BehaviorSubject pour un service de données car un service angular s’initialise souvent avant le composant et le comportement comportement garantissent que le composant qui utilise le service reçoit la dernière mise à jour données même s'il n'y a pas de nouvelles mises à jour depuis l'abonnement du composant à ces données.

796
Shantanu Bhadoria

Observable: Résultat différent pour chaque observateur

Une différence très très importante. Comme Observable n’est qu’une fonction, il n’a pas d’état. Par conséquent, chaque nouvel observateur exécute le code de création observable, encore et encore. Cela se traduit par:

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

Cela provoque des bugs majeurs et des inefficacités

BehaviorSubject (ou Subject) stocke les détails de l'observateur, n'exécute le code qu'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 avec Observable.create créé une sortie différente pour chaque observateur, alors que BehaviorSubject donne la même sortie pour tous les observateurs. C'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                          │
└─────────────────────────────────────┴─────────────────────────────────────┘
136
Vamshi

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

Les interfaces Observer et Observable fournissent un mécanisme généralisé pour la notification Push, également connu sous le nom de modèle de conception d'observateur. L'objet Observable représente l'objet qui envoie des 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'observateur, en ce sens qu'elle est à la fois observateur et observable. Vous pouvez utiliser un sujet pour abonner tous les observateurs, puis abonner le sujet à une source de données principale.

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();

Plus sur https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/subjects.md

26
Md Ayub Ali Sarker

Observable et le sujet est un moyen d'observation qui permet à l'observateur de le suivre. mais les deux ont des caractéristiques uniques. En outre, il existe au total 3 types de sujets, chacun d’eux présentant à nouveau des caractéristiques uniques. Essayons de comprendre chacun d'eux.

vous pouvez trouver l'exemple pratique ici sur stackblitz . (Vous devez vérifier la console pour voir le résultat réel)

enter image description here

Observables

Ils sont froids: Le code est exécuté quand ils ont au moins un observateur.

Crée une copie des données: Observable crée une copie des données pour chaque observateur.

Unidirectionnel: L'observateur ne peut pas affecter de valeur à observable (Origine/maître).

Subject

Ils sont chauds: le code est exécuté et la valeur est diffusée même s'il n'y a pas d'observateur.

Partage des données: Les mêmes données sont partagées par tous les observateurs.

bidirectionnel: L'observateur peut affecter une valeur à observable (Origine/maître).

Si vous utilisez un sujet, toutes les valeurs diffusées avant la création de l'observateur sont manquantes. Alors, voici sujet de relecture

ReplaySubject

Ils sont chauds: le code est exécuté et la valeur est diffusée même s'il n'y a pas d'observateur.

Partage des données: Les mêmes données sont partagées par tous les observateurs.

bidirectionnel: L'observateur peut affecter une valeur à observable (Origine/maître). plus

Rejouer le flux de messages: Peu importe le moment où vous vous abonnez au sujet de la relecture, vous recevez tous les messages diffusés. .

Dans subject et replay, vous ne pouvez pas définir la valeur initiale sur observable. Alors, voici Sujet comportemental

BehaviorSubject

Ils sont chauds: le code est exécuté et la valeur est diffusée même s'il n'y a pas d'observateur.

Partage des données: Les mêmes données sont partagées par tous les observateurs.

bidirectionnel: L'observateur peut affecter une valeur à observable (Origine/maître). plus

Rejouer le flux de messages: Peu importe le moment où vous vous abonnez au sujet de la relecture, vous recevez tous les messages diffusés. .

Vous pouvez définir la valeur initiale: Vous pouvez initialiser l'observable avec la valeur par défaut.

25
Kedar9444

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

C’est un peu délicat, car les bibliothèques exposent souvent les champs de manière observable (paramètres dans ActivatedRoute dans Angular2), mais peuvent utiliser Subject ou BehaviorSubject en coulisse. Ce qu'ils utilisent aurait une incidence sur le comportement des abonnés.

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);
16

Un observable vous permet de vous abonner uniquement, alors qu'un sujet vous permet de publier et de vous abonner.

Ainsi, un sujet permet à votre services d'être utilisé à la fois comme éditeur et comme abonné.

Pour l'instant, je ne suis pas si bon en Observable alors je ne partagerai qu'un exemple de Subject.

Comprenons mieux avec un exemple angulaire CLI . Exécutez les commandes ci-dessous:

npm install -g @angular/cli

ng new angular2-subject

cd angular2-subject

ng serve

Remplacez le contenu de app.component.html par:

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

<app-home>
</app-home>

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

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

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

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

Importez Subject dans MessageService. Ajouter un sujet aussi. Le code final doit ressembler à 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 transmettez-en une instance 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);
  }
}

Dans app.component.ts, abonnez-vous et désabonnez-vous (pour éviter les fuites de mémoire) à la 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 ça.

Maintenant, toute valeur entrée dans #message sur home.component.html sera imprimée sur {{message}} dans app.component.html

9
student

app.component.ts

behaviourService.setName("behaviour");

behavior.ervice.ts

private name = new BehaviorSubject("");
getName = this.name.asObservable();`

constructor() {}

setName(data) {
  this.name.next(data);
}

custom.component.ts

behaviourService.subscribe(response=>{
  console.log(response);    //output: behaviour
});
2
Chandru Dev

BehaviorSubject vs Observable: RxJS a des observateurs et des observables, Rxjs propose plusieurs classes à utiliser avec des flux de données, dont l’un est BehaviorSubject.

Observables: Les observables sont des collections paresseuses de valeurs multiples dans le temps.

BehaviorSubject: Sujet nécessitant une valeur initiale et émettant sa valeur actuelle aux nouveaux abonnés.

 // RxJS v6+
import { BehaviorSubject } from 'rxjs';

const subject = new BehaviorSubject(123);

//two new subscribers will get initial value => output: 123, 123
subject.subscribe(console.log);
subject.subscribe(console.log);

//two subscribers will get new value => output: 456, 456
subject.next(456);

//new subscriber will get latest value (456) => output: 456
subject.subscribe(console.log);

//all three subscribers will get new value => output: 789, 789, 789
subject.next(789);

// output: 123, 123, 456, 456, 456, 789, 789, 789
0
Flash