kevin marca
Estoy investigando los patrones de diseño de RxJS y no entiendo la diferencia entre BehaviorSubject
y Observable
.
Según tengo entendido, BehaviorSubject puede contener un valor que puede cambiar. Se puede suscribir y los suscriptores pueden recibir valores actualizados. Ambos parecen tener exactamente el mismo propósito.
- ¿Cuándo se debe usar Observable vs BehaviorSubject y viceversa?
- ¿Cuáles son los beneficios de usar BehaviorSubject en lugar de Observable y viceversa?
Shantanu Bhadoria
BehaviorSubject
es una variante de Subject
un tipo de Observable
al que uno puede “suscribirse” como cualquier otro Observable.
Características de BehaviorSubject
- Necesita un valor inicial ya que siempre debe devolver un valor al momento de la suscripción, incluso si no ha recibido el método
next()
- Tras la suscripción, devuelve el último valor del Asunto. Un Observable normal solo se activa cuando recibe el método
onNext()
- En cualquier momento, uno puede recuperar el último valor del Sujeto en un no Observable usando el método
getValue()
Características del tema
- El sujeto es un “observador” además de ser un Observable; por lo tanto, también se pueden enviar valores a un Sujeto mientras se está suscrito a él
- Uno puede obtener un valor de BehaviorSubject usando el método
asObservable()
Ejemplo 1 usando BehaviorSubject
// BehaviorSubject.
// 'A' is an initial value. If there is a Subscription
// after it, it would immediately get the value 'A'.
beSubject = new BehaviorSubject('a');
beSubject.next('b');
beSubject.subscribe(value => {
console.log('Subscription received the value ', value);
// Subscription received B. It would not happen
// for an Observable or Subject by default.
});
beSubject.next('c');
// Subscription received C.
beSubject.next('d');
// Subscription received D.
Ejemplo 2 usando Asunto
// Subject.
subject = new Subject();
subject.next('b');
subject.subscribe(value => {
console.log('Subscription received the value ', value);
// Subscription won't receive anything at this point.
});
subject.next('c');
// Subscription received C.
subject.next('d');
// Subscription received D.
Se puede crear un Observable a partir de ambos Subject
y BehaviorSubject
; Por ejemplo, subjectName.asObservable()
.
La única diferencia es que no se pueden enviar valores a un Observable usando el método next()
.
En Angular, se recomienda usar BehaviorSubject
para transferir datos como un servicio a menudo se inicializa antes que un componente.
BehaviorSubject garantiza que el componente que consume el Servicio reciba los últimos datos actualizados, incluso si no hay nuevas actualizaciones, debido a la suscripción del componente al Servicio.
-
Estoy un poco confundido con el ejemplo 2 del tema regular. ¿Por qué la suscripción no obtendrá nada aunque en la segunda línea envíe valores al sujeto usando subject.next(“b”)?
– jmod999
11/11/2016 a las 17:45
-
@jmod999 El segundo ejemplo es un sujeto regular que recibe un valor justo antes de que se llame a la suscripción. En asuntos regulares, la suscripción solo se activa para los valores recibidos después de que se llama la suscripción. Como se recibe justo antes de la suscripción, no se envía a la suscripción.
– Shantanu Bhadoria
19/04/2017 a las 19:20
-
Tuve una entrevista con Angular 4 el miércoles. Como todavía estoy aprendiendo sobre la nueva plataforma, me hizo tropezar preguntándome algo como “¿Qué sucederá si me suscribo a un observable que está en un módulo que aún no se ha cargado de forma diferida?” No estaba seguro, pero me dijo que la respuesta era usar un BSubject, EXACTAMENTE como lo explicó el Sr. Bhadoria arriba. La respuesta fue usar un BSubject porque siempre devuelve el valor más reciente (al menos así es como recuerdo el comentario final del entrevistador al respecto).
– bob.mazzo
24 de noviembre de 2017 a las 15:48
-
@bob.mazzo ¿Por qué necesito usar un BSubject para ese caso? — Si me suscribo a ese Observer, no recibiré nada porque el observador no se ha inicializado, por lo que no puede enviar datos a los observadores y si uso un BSubject, tampoco recibiré nada por la misma razón. En ambos casos, el suscriptor no recibirá nada porque está dentro de un módulo que no ha sido inicializado. ¿Tengo razón?
–Rafael Reyes
13 de junio de 2018 a las 23:03
-
¿No debería el servicio tener un privado?
BehaviourSubject
y el valor se accede desde un públicoObservable
que emite el valor de laBehaviourSubject
para no permitirnext
siendo llamado en elBS
fuera del servicio?– Emobe
5 de junio de 2019 a las 10:08
Vamshi
Observable: resultado diferente para cada observador
Una diferencia muy muy importante. Dado que Observable es solo una función, no tiene ningún estado, por lo que para cada nuevo Observer, ejecuta el código de creación observable una y otra vez. Esto resulta en:
El código se ejecuta para cada observador. Si es una llamada HTTP, se llama para cada observador
Esto provoca importantes errores e ineficiencias.
BehaviorSubject (o Asunto) almacena los detalles del observador, ejecuta el código solo una vez y proporciona el resultado a todos los observadores.
Ex:
JSBin: http://jsbin.com/qowulet/edit?js,consola
// --- 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>
Producción :
"observer 1: 0.7184075243594013"
"observer 2: 0.41271850211336103"
"observer subject 1: 0.8034263165479893"
"observer subject 2: 0.8034263165479893"
Observa cómo usando Observable.create
creó una salida diferente para cada observador, pero BehaviorSubject
dio la misma salida para todos los observadores. Esto es importante.
Otras diferencias resumidas.
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 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 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
-
cualquiera que venga de
KnockoutJS's ko.observable()
inmediatamente verá más paralelismos conRx.BehaviorSubject
en comparación conRx.Observable
– Simón_Weaver
21 de junio de 2017 a las 21:57
-
@Skeptor Observable: El método subscribe siempre activará el método onNext asociado con el observador y traerá el valor de retorno. ComportamientoAsunto/Asunto: Siempre devolverá el valor más reciente en la transmisión. aquí el método de suscripción con el sujeto no activará el método Siguiente de su observador hasta que encuentre el valor más reciente en la transmisión.
– Mohan Ram
26 de octubre de 2017 a las 10:58
cedar9444
Observable y Sujeto Ambos son observables, lo que significa que un observador puede rastrearlos. Ambos tienen algunas características únicas. Hay 3 tipos de Sujetos, cada uno de los cuales también tiene características únicas.
Puede encontrar el ejemplo práctico aquí en apilar.
(Debe verificar la consola para ver la salida real)
Observables
Están fríos: El código se ejecuta cuando tienen al menos un único observador.
Crea una copia de los datos: Observable crea una copia de los datos para cada observador.
Unidireccional: El observador no puede asignar valor a observable (origen/maestro).
Subject
Están calientes: el código se ejecuta y el valor se transmite incluso si no hay un observador.
Comparte datos: Los mismos datos se comparten entre todos los observadores.
bidireccional: El observador puede asignar valor a observable (origen/maestro).
Si está utilizando sujeto, perderá todos los valores que se transmiten antes de la creación del observador. Así que aquí viene Asunto de reproducción
ReplaySubject
Están calientes: el código se ejecuta y el valor se transmite incluso si no hay un observador.
Comparte datos: Los mismos datos se comparten entre todos los observadores.
bidireccional: El observador puede asignar valor a observable (origen/maestro). más
Reproducir el flujo de mensajes: No importa cuándo te suscribas al asunto de la repetición, recibirás todos los mensajes transmitidos.
En Subject y ReplaySubject, no puede establecer el valor inicial en observable. Así que aquí viene Sujeto conductual…
BehaviorSubject
Están calientes: el código se ejecuta y el valor se transmite incluso si no hay un observador.
Comparte datos: Los mismos datos se comparten entre todos los observadores.
bidireccional: El observador puede asignar valor a observable (origen/maestro). más
Reproducir el flujo de mensajes: No importa cuándo te suscribas al asunto de la repetición, recibirás todos los mensajes transmitidos.
Puede establecer el valor inicial: Puede inicializar el observable con un valor predeterminado.
-
Podría valer la pena mencionar que un
ReplaySubject
tiene un historial y puede transmitir/emitir una secuencia de valores (antiguos). Solo cuando el búfer se establece en 1, se comporta de manera similar a unBehaviorSubject
.– Marchitez
19 de noviembre de 2019 a las 8:29
-
Para BehaviorSubject, el párrafo “Reproducir el flujo de mensajes” parece no ser correcto
– Jaqen H´ghar
19 de diciembre de 2020 a las 7:48
El objeto Observable representa una colección basada en push.
Las interfaces Observer y Observable proporcionan un mecanismo generalizado para la notificación automática, también conocido como patrón de diseño del observador. El objeto Observable representa el objeto que envía notificaciones (el proveedor); el objeto Observer representa la clase que los recibe (el observador).
La clase Sujeto hereda tanto Observable como Observer, en el sentido de que es tanto un observador como un observable. Puede usar un tema para suscribir a todos los observadores y luego suscribir el tema a una fuente de datos de back-end
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();
Más en https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/subjects.md
Una cosa que no veo en los ejemplos es que cuando lanzas BehaviorSubject a Observable a través de asObservable, hereda el comportamiento de devolver el último valor en la suscripción.
Es la parte complicada, ya que a menudo las bibliotecas exponen los campos como observables (es decir, parámetros en ActivatedRoute en Angular2), pero pueden usar Subject o BehaviorSubject detrás de escena. Lo que usan afectaría el comportamiento de suscripción.
Mira aquí http://jsbin.com/ziquxapubo/edit?html,js,consola
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 le permite suscribirse sólo mientras que un sujeto le permite tanto publicar como suscribirse.
Así que un sujeto le permite a su servicios para ser utilizado como editor y suscriptor.
A partir de ahora, no soy tan bueno en Observable
así que compartiré solo un ejemplo de Subject
.
Entendamos mejor con un CLI angular ejemplo. Ejecute los siguientes comandos:
npm install -g @angular/cli
ng new angular2-subject
cd angular2-subject
ng serve
Reemplazar el contenido de app.component.html
con:
<div *ngIf="message">
{{message}}
</div>
<app-home>
</app-home>
Ejecute el comando ng g c components/home
para generar el componente de inicio. Reemplazar el contenido de home.component.html
con:
<input type="text" placeholder="Enter message" #message>
<button type="button" (click)="setMessage(message)" >Send message</button>
#message
es la variable local aquí. Agregar una propiedad message: string;
hacia
app.component.ts
‘clase S.
Ejecute este comando ng g s service/message
. Esto generará un servicio en src\app\service\message.service.ts
. Proporcione este servicio a la aplicación.
Importar Subject
en MessageService
. Agrega un tema también. El código final se verá así:
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
}
}
Ahora, inyecte este servicio en home.component.ts
y pasar una instancia de él al constructor. haz esto por app.component.ts
también. Use esta instancia de servicio para pasar el valor de #message
a la función de servicio 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);
}
}
Adentro app.component.ts
suscríbase y cancele la suscripción (para evitar pérdidas de memoria) al 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();
}
}
Eso es todo.
Ahora, cualquier valor ingresado dentro #message
de home.component.html
se imprimirá a {{message}}
adentro app.component.html
R4L_R4o
Pensar en observables como una tubería con agua que fluye, a veces el agua fluye ya veces no. En algunos casos, es posible que necesite una tubería que siempre tenga agua, puede hacerlo creando una tubería especial que siempre contenga agua sin importar cuán pequeña sea, llamemos a esta tubería especial ComportamientoAsuntosi usted es un proveedor de suministro de agua en su comunidad, puede dormir tranquilo por la noche sabiendo que su tubería recién instalada simplemente funciona.
En términos técnicos: puede encontrar casos de uso en los que un Observable siempre debería tener valor, tal vez desee capturar el valor de un texto de entrada a lo largo del tiempo, luego puede crear una instancia de BehaviorSubject para garantizar este tipo de comportamiento, digamos:
const firstNameChanges = new BehaviorSubject("<empty>");
// pass value changes.
firstNameChanges.next("Jon");
firstNameChanges.next("Arya");
A continuación, puede utilizar “valor” para probar los cambios a lo largo del tiempo.
firstNameChanges.value;
Esto es útil cuando combina Observables más tarde, al observar el tipo de su transmisión como BehaviorSubject, puede asegurarse de que el transmita al menos incendios o señale solo una vez al menos.
-
cubre muchas partes, pero el lado positivo de su explicación es que brinda una analogía fácil de entender, ¡Kudo!
– Jeb50
2 abr 2021 a las 21:59
Este artículo me ayudó especialmente a comprender los observables frente a los sujetos frente a los sujetos de comportamiento en la forma ELI5. javascript.plainenglish.io/…
– Mike.Álvarez
31 de agosto de 2021 a las 15:06