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?
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:
next()
.onnext
getValue()
.Les caractéristiques uniques d'un sujet par rapport à un observable sont les suivantes:
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.
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 │
└─────────────────────────────────────┴─────────────────────────────────────┘
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
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)
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.
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);
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
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
});
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