Поведение субъекта против наблюдаемого?
Я смотрю на угловые шаблоны RxJs, и я не понимаю разницы между a BehaviorSubject и Observable.
из моего понимания, a BehaviorSubject - Это значение, которое может изменяться с течением времени (может быть подписано на и подписчики могут получать обновленные результаты). Это, кажется, та же самая цель Observable.
когда вы используете Observable против BehaviorSubject? Есть ли преимущества в использовании BehaviorSubject на Observable или наоборот?
5 ответов:
BehaviorSubject это тип субъекта, субъект-это особый тип наблюдаемого, поэтому вы можете подписаться на сообщения, как и на любые другие наблюдаемые. Уникальными особенностями BehaviorSubject являются:
- он должен начальное значение так как он всегда должен возвращать значение по подписке, даже если он не получил
next()- при подписке он возвращает последнее значение темы. Регулярное наблюдаемое срабатывает только тогда, когда оно получает
onnext- в любой момент Вы можете получить последнее значение субъекта в ненаблюдаемом коде, используя
getValue()метод.уникальными особенностями субъекта по сравнению с наблюдаемым являются:
- это наблюдатель в дополнение к тому, чтобы быть наблюдаемым, поэтому вы также можете отправлять значения субъекту в дополнение к подписке на него.
кроме того, вы можете получить наблюдаемый от субъекта поведения с помощью
asObservable()методBehaviorSubject.наблюдаемых является общим, и
BehaviorSubjectтехнически является подтипом наблюдаемого, потому что 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()метод.в угловых службах я бы использовал
BehaviorSubjectдля службы данных в качестве угловой службы часто инициализируется перед компонентом и субъект поведения гарантирует, что компонент, потребляющий службу, получает последние обновленные данные, даже если нет новых обновлений с момента подписки компонента на эти данные.
наблюдаемый: разные результаты для каждого наблюдателя
одно очень важное различие. Поскольку Observable-это просто функция, она не имеет никакого состояния, поэтому для каждого нового наблюдателя она снова и снова выполняет наблюдаемый код create. Это приводит к:
код выполняется для каждого наблюдателя . Если это вызов HTTP, он вызывается для каждого наблюдателя
это вызывает серьезные ошибки и недостатки
BehaviorSubject (или субъект ) сохраняет данные наблюдателя, выполняет код только один раз и дает результат всем наблюдателям .
пример:
JSBin:http://jsbin.com/qowulet/edit?js, консоль
// --- 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>выход :
"observer 1: 0.7184075243594013" "observer 2: 0.41271850211336103" "observer subject 1: 0.8034263165479893" "observer subject 2: 0.8034263165479893"наблюдать, как с помощью
Observable.createсоздал разные выходные данные для каждого наблюдателя, ноBehaviorSubjectдал тот же результат для всех наблюдателей. Это очень важно.
другие различия резюмировать.
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ 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 │ └─────────────────────────────────────┴─────────────────────────────────────┘
наблюдаемый объект представляет коллекцию на основе push.
наблюдатель и наблюдаемые интерфейсы обеспечивают обобщенный механизм для уведомления на основе push, также известный как шаблон проектирования наблюдателя. Объект 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
одна вещь, которую я не вижу в примерах, заключается в том, что когда вы приводите BehaviorSubject к Observable через asObservable, он наследует поведение возврата последнего значения по подписке.
Это сложный бит, так как часто библиотеки будут выставлять поля как наблюдаемые (т. е. params в ActivatedRoute в Angular2), но могут использовать субъект или BehaviorSubject за кулисами. То, что они используют, повлияет на поведение подписки.
см. здесь http://jsbin.com/ziquxapubo/edit?html,js, консоль
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);
An наблюдаемых позволяет подписаться только тогда, когда a теме позволяет как публиковать, так и подписываться.
так что тема позволяет ваш услуги для использования в качестве издателя и подписчика.
на данный момент, я не так хорош в
Observableпоэтому я поделюсь только примерSubject.давайте лучше разберемся с угловой 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 g c components/homeдля создания компонента home. Замените содержимоеhome.component.htmlС:<input type="text" placeholder="Enter message" #message> <button type="button" (click)="setMessage(message)" >Send message</button>
#messageявляется локальной переменной здесь. Добавьте свойствоmessage: string;до 'ы.выполнить команду
ng g s 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и передать экземпляр его конструктору. Сделайте это для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
Comments