BehaviorSubject vs Observable?

Я изучаю паттерны Angular RxJs и не понимаю разницу между BehaviorSubject и Observable.

Насколько я понимаю, BehaviorSubject - это значение, которое может меняться со временем (на него можно подписаться, и подписчики могут получать обновленные результаты). Похоже, что это та же самая цель Observable.

Когда бы вы использовали Observable против BehaviorSubject? Есть ли преимущества в использовании BehaviorSubject сравнению с Observable или наоборот?

Ответ 1

BehaviorSubject - это тип субъекта, субъект - это особый тип наблюдаемых, поэтому вы можете подписываться на сообщения, как и любые другие наблюдаемые. Уникальные особенности BehaviorSubject:

  • Ему нужно начальное значение, так как он всегда должен возвращать значение в подписке, даже если он не получил next()
  • При подписке возвращает последнее значение темы. Обычная наблюдаемая срабатывает только тогда, когда она получает onnext
  • в любой момент вы можете получить последнее значение субъекта в ненаблюдаемом коде, используя метод getValue().

Уникальные особенности предмета по сравнению с наблюдаемым:

  • Это наблюдатель в дополнение к тому, что он является наблюдаемым, поэтому вы также можете отправлять значения субъекту в дополнение к подписке на него.

Кроме того, вы можете получить наблюдаемое от субъекта поведения, используя метод asObservable() в BehaviorSubject.

Observable - это Generic, а BehaviorSubject технически является подтипом Observable, потому что BehaviorSubject является наблюдаемым с определенными качествами.

Пример с 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

Пример 2 с обычной темой:

// 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

Наблюдаемые могут быть созданы как из Subject и из BehaviorSubject с использованием subject.asObservable().

Разница лишь в том, что вы не можете отправлять значения наблюдаемой с помощью метода next().

В сервисах Angular я бы использовал BehaviorSubject для службы данных, так как служба Angular часто инициализируется до того, как компонент и субъект поведения гарантируют, что компонент, использующий службу, получит последние обновленные данные, даже если нет новых обновлений с момента подписки компонента на эти данные.

Ответ 2

Наблюдаемые: разные результаты для каждого наблюдателя

Одно очень очень важное отличие. Поскольку Observable - это просто функция, у нее нет состояния, поэтому для каждого нового Observer он снова и снова выполняет наблюдаемый код создания. Это приводит к:

Код запускается для каждого наблюдателя. Если это вызов HTTP, он вызывается для каждого наблюдателя

Это вызывает серьезные ошибки и неэффективность

BehaviorSubject (или Subject) хранит данные наблюдателя, запускает код только один раз и передает результат всем наблюдателям.

Пример:

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>

Ответ 3

Объект Observable представляет собой коллекцию на основе push.

Интерфейсы Observer и Observable обеспечивают обобщенный механизм push-on-уведомления, также известный как шаблон проектирования наблюдателя. Объект Observable представляет объект, который отправляет уведомления (поставщик); объект Observer представляет класс, который их получает (наблюдатель).

Класс Subject наследует как Observable, так и Observer в том смысле, что он является наблюдателем и наблюдаемым. Вы можете использовать субъекта для подписки на всех наблюдателей, а затем подписывать субъекта на исходный источник данных

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

Подробнее о https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/subjects.md

Ответ 4

Наблюдаемый и субъект оба являются наблюдаемыми, значит, наблюдатель может отслеживать их. но оба они имеют некоторые уникальные характеристики. Далее есть всего 3 типа предметов, каждый из которых снова имеет уникальные характеристики. Давайте попробуем понять каждого из них.

Вы можете найти практический пример здесь на stackblitz. (Вам нужно проверить консоль, чтобы увидеть фактический вывод)

enter image description here

Observables

Они холодные: код выполняется, когда у них есть хотя бы один наблюдатель.

Создает копию данных: Observable создает копию данных для каждого наблюдателя.

Однонаправленный: наблюдатель не может присвоить значение наблюдаемому (происхождение/мастер).

Subject

Они горячие: код выполняется и значение транслируется, даже если нет наблюдателя.

Данные об акциях: одни и те же данные передаются всем наблюдателям.

двунаправленный: наблюдатель может присвоить значение наблюдаемому (источник/мастер).

Если вы используете использование темы, то вы пропустите все значения, которые транслируются до создания наблюдателя. Так что вот идет Replay Subject

ReplaySubject

Они горячие: код выполняется и значение транслируется, даже если нет наблюдателя.

Данные об акциях: одни и те же данные передаются всем наблюдателям.

двунаправленный: наблюдатель может присвоить значение наблюдаемому (источник/мастер). плюс

Воспроизведение потока сообщений. Независимо от того, когда вы подпишитесь на тему воспроизведения, вы будете получать все передаваемые сообщения.

В теме и воспроизведении темы вы не можете установить начальное значение на наблюдаемое. Так что вот идет Поведенческий предмет

BehaviorSubject

Они горячие: код выполняется и значение транслируется, даже если нет наблюдателя.

Данные об акциях: одни и те же данные передаются всем наблюдателям.

двунаправленный: наблюдатель может присвоить значение наблюдаемому (источник/мастер). плюс

Воспроизведение потока сообщений. Независимо от того, когда вы подпишитесь на тему воспроизведения, вы будете получать все передаваемые сообщения.

Вы можете установить начальное значение: Вы можете инициализировать наблюдаемое значение по умолчанию.

Ответ 5

Одна вещь, которую я не вижу в примерах, состоит в том, что когда вы приводите BehaviorSubject к Observable через asObservable, он наследует поведение возврата последнего значения в подписке.

Это хитрый момент, так как часто библиотеки будут выставлять поля как наблюдаемые (т.е. параметры в ActivatedRoute в Angular2), но могут использовать Subject или BehaviorSubject за кулисами. То, что они используют, повлияет на поведение подписки.

Смотрите здесь 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);

Ответ 6

Наблюдаемое позволяет вам подписываться только тогда, когда тема позволяет вам публиковать и подписываться.

Таким образом, субъект позволяет использовать ваши услуги как издателя, так и подписчика.

На данный момент я не очень хорош в Observable поэтому я поделюсь только примером Subject.

Давайте лучше разберемся с примером Angular CLI. Запустите следующие команды:

npm install -g @angular/cli

ng new angular2-subject

cd angular2-subject

ng serve

Замените содержимое app.component.html:

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

<app-home>
</app-home>

Запустите команду ng gc components/home чтобы создать домашний компонент. Замените содержимое home.component.html:

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

#message является локальной переменной здесь. Добавить message: string; свойства message: string; в класс app.component.ts.

Запустите эту команду ng gs service/message. Это создаст службу в src\app\service\message.service.ts. Предоставьте эту услугу приложению.

Импортировать Subject в MessageService. Добавьте тему тоже. Окончательный код должен выглядеть так:

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
  }
}

Теперь home.component.ts этот сервис в home.component.ts и передайте его экземпляр конструктору. Сделайте это и для app.component.ts. Используйте этот экземпляр сервиса для передачи значения #message в сервисную функцию 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);
  }
}

Внутри app.component.ts подписаться и отписаться (чтобы предотвратить утечки памяти) на 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();
  }
}

Это.

Теперь любое значение, введенное внутри #message из home.component.html должно быть напечатано в {{message}} внутри app.component.html

Ответ 7

app.component.ts

behaviourService.setName("behaviour");

behaviour.service.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
});

Ответ 8

Удобная сводка различных наблюдаемых типов.

  • Subject - подписчик получит опубликованные значения только после подписки.
  • BehaviorSubject - Новые подписчики получают последнее опубликованное значение ИЛИ начальное значение сразу после подписки.
  • ReplaySubject - Новые подписчики получают последние 1-n опубликованных значений сразу после подписки (только если они были отправлены ранее).

Ответ 9

BehaviorSubject vs Observable: RxJS имеет наблюдателей и наблюдаемых, Rxjs предлагает несколько классов для использования с потоками данных, и один из них - BehaviorSubject.

Observables: Observables - это ленивые коллекции нескольких значений с течением времени.

BehaviorSubject: субъект, которому требуется начальное значение и который выдает текущее значение новым подписчикам.

 // 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