¿Cuál es la diferencia entre BehaviorSubject y Observable?
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 utilizar Observable frente a BehaviorSubject y viceversa?
- ¿Cuáles son los beneficios de utilizar BehaviorSubject en lugar de Observable y viceversa?
BehaviorSubject
es una variante de Subject
, un tipo 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()
- Al suscribirse, devuelve el último valor del Asunto. Un Observable normal solo se activa cuando recibe el método.
onNext()
- En cualquier momento, se puede recuperar el último valor del Asunto 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 Asunto y al mismo tiempo suscribirse a él.
- Se 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 usarlo BehaviorSubject
para transferir datos, ya que 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.
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 Observador, 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 causa errores e ineficiencias importantes.
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,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>
Producción :
"observer 1: 0.7184075243594013"
"observer 2: 0.41271850211336103"
"observer subject 1: 0.8034263165479893"
"observer subject 2: 0.8034263165479893"
Observe cómo el uso Observable.create
creó resultados diferentes para cada observador, pero BehaviorSubject
dio el mismo resultado 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 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Tanto Observable como Sujeto 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 stackblitz . (Debe verificar la consola para ver el resultado real)
Observables
Son fríos: el código se ejecuta cuando tienen al menos un observador.
Crea una copia de los datos: Observable crea una copia de los datos para cada observador.
Unidireccional: el observador no puede asignar valor al observable (origen/maestro).
Subject
Están de moda: 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 al observable (origen/maestro).
Si utiliza el sujeto, se perderán todos los valores que se transmiten antes de la creación del observador. Así que aquí viene el asunto de la repetición.
ReplaySubject
Están de moda: 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 al observable (origen/maestro). más
Reproduzca la transmisión de mensajes: no importa cuándo se suscriba al asunto de la reproducción, recibirá todos los mensajes transmitidos.
En Asunto y ReplaySubject, no puede establecer el valor inicial en observable. Así que aquí viene BehavioralSubject ...
BehaviorSubject
Están de moda: 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 al observable (origen/maestro). más
Puede establecer un valor inicial: puede inicializar el observable con un valor predeterminado.
El objeto Observable representa una colección basada en push.
Las interfaces Observer y Observable proporcionan un mecanismo generalizado para notificaciones push, también conocido como patrón de diseño de observador. El objeto Observable representa el objeto que envía notificaciones (el proveedor); el objeto Observador representa la clase que los recibe (el observador).
La clase Asunto hereda tanto Observable como Observador, en el sentido de que es a la vez observador y observable. Puede utilizar un asunto para suscribir a todos los observadores y luego suscribir el asunto a una fuente de datos de backend.
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 información sobre https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/subjects.md