Subject vs BehaviorSubject vs ReplaySubject у кутовій


124

Я шукав, щоб зрозуміти ці 3:

Тема , Тема поведінки та Тема відтворення . Я хотів би їх використовувати і знати, коли і навіщо, які переваги від їх використання, і хоча я читав документацію, дивився підручники та шукав Google, я цього не мав сенсу.

То яке їх призначення? Справа в реальному світі була б найкраще оцінена, її не потрібно навіть кодувати.

Я вважаю за краще чітке пояснення не просто "a + b => c ви підписані на ...."

Дякую


1
Вже є питання щодо теми поведінки, що спостерігається; stackoverflow.com/questions/39494058/… та документація щодо теми повтору зрозуміла imo github.com/Reactive-Extensions/RxJS/blob/master/doc/api/…
еко

Існує досить ретельне виклад предметів в Rxjs в цьому відповіді , який доповнює добре відповідь від peeksilet. Сюди входять також важливі деталі щодо поведінки після припинення, тому добре придивитися.
користувач3743222

Відповіді:


278

Це дійсно зводиться до поведінки та семантики. З

  • Subject- абонент отримуватиме лише опубліковані значення, які були випромінені після підписки. Запитайте себе, це те, чого ви хочете? Чи потрібно абоненту щось знати про попередні значення? Якщо ні, то ви можете використовувати це, інакше виберіть один із інших. Наприклад, з комунікацією між компонентами. Скажімо, у вас є компонент, який публікує події для інших компонентів натисканням кнопки. Ви можете використовувати послугу з предметом для спілкування.

  • BehaviorSubject- кешується останнє значення. Абонент отримує останнє значення після початкової підписки. Семантика для цього предмета полягає у поданні значення, яке змінюється з часом. Наприклад, зареєстрований користувач. Початковий користувач може бути анонімним. Але як тільки користувач входить у систему, новим значенням є стан автентифікованого користувача.

    BehaviorSubjectІніціалізується з початковим значенням. Іноді це важливо для переваги кодування. Скажімо, наприклад, ви ініціалізуєте його з a null. Потім у вашій підписці потрібно зробити нульову перевірку. Може, гаразд, а може і дратує.

  • ReplaySubject- він може кешувати до визначеної кількості викидів. Будь-які абоненти отримують усі кешовані значення після підписки. Коли вам знадобиться така поведінка? Чесно кажучи, у мене не було потреби в такій поведінці, за винятком наступного випадку:

    Якщо ви ініціалізуєте a ReplaySubjectз розміром буфера 1, то він насправді поводиться так, як BehaviorSubject. Останнє значення завжди кешоване, тому воно діє як значення, що змінюється з часом. З цим немає необхідності nullперевіряти, як у випадку BehaviorSubjectініціалізованої з a null. У цьому випадку перед підписчиком жодне значення ніколи не видається.

Таким чином, це дійсно зводиться до поведінки, яку ви очікуєте (щодо того, яку саме використовувати). Більшу частину часу ви, ймовірно, захочете використовувати, BehaviorSubjectоскільки те, що ви насправді хочете представляти, - це семантичне значення в часі. Але я особисто не бачу нічого поганого в заміні ReplaySubjectініціалізованого на 1.

Те, що ви хочете уникати, - це використання ванілі, Subjectколи ви дійсно потребуєте певного кешування. Візьмемо для прикладу, що ви пишете захист від маршрутизації або рішення Ви отримуєте деякі дані в цьому захисті і встановлюєте їх у службу Subject. Потім у маршрутизованому компоненті ви підписуєтесь на тему послуги, щоб спробувати отримати те значення, яке було випромінено у захисті. ООП. Де значення? Це вже було випромінено, DUH. Використовуйте тему "кешування"!

Дивитися також:


1
Це коротко і легко зрозуміти відмінності. Коли значення в сервісі змінюються і компоненти також змінюються, що відображається значення, тоді рішенням є BehaviourSubjects або Replay Subject.
Saiyaff Farouk

1
Дякую! ReplaySubjectз розміром буфера 1 було саме те, що мені потрібно. У мене був охоронець маршруту, який потребував значення, але потрібно було чекати першої емісії. Отже, це BehaviorSubjectне було його скорочення, оскільки я не хотів початкового значення ( nullне працював би навіть тому, що використовував його для позначення стану)
menehune23

1
@ menehune23 Мені також потрібен ReplaySubject для resolveкласу Angular Guard. Моя служба даних може бути асинхронною або синхронною (якщо дані вже були отримані). Якщо він був синхронним, Subject.next () був запущений до того, як resolveфункція повернулася та підписалася Angular внутрішньо. BehaviourSubject, можливо, спрацює, але мені доведеться чітко зателефонувати complete()та також додати nullчеки на початкове значення. Що працювало, було новим ReplaySubject<DataType>(1) іresolveSubject.asObservable().take(1).map(....)
Дренай

1
Я використовую ReplaySubject з розміром буфера 1, але чомусь, коли я отримую Observable with Observable, .asObservable()надсилаю значення nullабонентам, перш ніж я коли-небудь дзвоню next()на свій ReplaySubject. Я думав, що це не повинно мати початкове значення на відміну від BehaviorSubject?
Кайл В.

2
Я думаю, що досить легким прикладом, який ви могли б згадати для теми повтору, був би сценарій "чат" або ігрове лобі, де ви хочете, щоб нові столяри бачили останні 10 повідомлень.
Джеймс

16

Зручний підсумок різних типів, що спостерігаються, неінтуїтивне називання, я знаю, лол .

  • Subject - Абонент отримуватиме опубліковані значення лише після того, як підписка буде здійснена.
  • BehaviorSubject - Нові абоненти отримують останнє опубліковане значення АБО початкове значення відразу після підписки.
  • ReplaySubject - Нові абоненти отримують усі раніше опубліковані значення (і) відразу після підписки

1-n опублікованих значень? Так якби було 2 опублікованих значення, ReplaySubject видав би -1 опублікованих значень ???
Джейсон Ченг

@JasonCheng ні, він отримує всі опубліковані раніше значення підписки, оновіть відповідь :)
Ricky Boyce

11
  1. Тема : Після підписки він завжди отримує дані, які надсилаються після його підписки, тобто попередні висунуті значення не надходять .
const mySubject = new Rx.Subject();

mySubject.next(1);

const subscription1 = mySubject.subscribe(x => {
  console.log('From subscription 1:', x);
});

mySubject.next(2);

const subscription2 = mySubject.subscribe(x => {
  console.log('From subscription 2:', x);
});

mySubject.next(3);

subscription1.unsubscribe();

mySubject.next(4);

На цьому прикладі ось результат, який буде надруковано на консолі:

From subscription 1: 2
From subscription 1: 3
From subscription 2: 3
From subscription 2: 4

Зверніть увагу, як підписки, які надходять із запізненням, відсутні на деяких даних, які були внесені до теми.

  1. Повтор предметів : може допомогти, зберігаючи буфер попередніх значень, які будуть передані в нові підписки.

Ось приклад використання для предметів відтворення, де а buffer of 2 previous valuesзберігаються та випромінюються під час нових підписок:

const mySubject = new Rx.ReplaySubject(2);

mySubject.next(1);
mySubject.next(2);
mySubject.next(3);
mySubject.next(4);

mySubject.subscribe(x => {
  console.log('From 1st sub:', x);
});

mySubject.next(5);

mySubject.subscribe(x => {
  console.log('From 2nd sub:', x);
});

Ось що нам дає на консолі:

From 1st sub: 3
From 1st sub: 4
From 1st sub: 5
From 2nd sub: 4
From 2nd sub: 5
  1. Предмети поведінки : схожі на суб'єкти, що відтворюються, але будуть повторно випромінювати лише останнє випромінене значення або значення за замовчуванням, якщо раніше не було випущено жодне значення:
const mySubject = new Rx.BehaviorSubject('Hey now!');

mySubject.subscribe(x => {
  console.log('From 1st sub:', x);
});

mySubject.next(5);

mySubject.subscribe(x => {
  console.log('From 2nd sub:', x);
});

І результат:

From 1st sub: Hey now!
From 1st sub: 5
From 2nd sub: 5

Довідка: https://alligator.io/rxjs/subjects/


4

Від: Книга Рандалла Кутніка «Створення реактивних веб-сайтів за допомогою RxJS». :

Предмет є об'єктом, це турбований спостережуваним. За своєю суттю, Subject діє так, як звичайний спостережуваний, але кожна підписка підключена до одного джерела. Суб'єкти також є спостерігачами і мають наступні, помилкові та виконані методи для надсилання даних відразу всім підписникам. Оскільки суб'єкти є спостерігачами, вони можуть бути передані безпосередньо в підписку на підписку, і всі події з оригінального спостережуваного повідомлення будуть відправлені через тему його підписникам.

Ми можемо використовувати ReplaySubject для відстеження історії. ReplaySubject записує останні події і п palys їх назад до кожного нового абонента. Наприклад, у програмі для чату. Ми можемо використовувати його для відстеження запису попередньої історії чатів.

BehaviorSubject є спрощеною версією ReplaySubject . ReplaySubject зберігати довільну кількість подій, BehaviorSubject тільки записує значення останньої події. Щоразу, коли BehaviorSubject записує нову підписку, він видає останнє значення абоненту, а також будь-які нові значення, які передаються. Поведінка BehaviorSubject корисна при роботі з окремими одиницями стану, такими як параметри конфігурації.


1

Відповідь, що найбільше обґрунтовується, явно неправильна, стверджуючи:

"Якщо ви ініціалізуєте a ReplaySubjectз розміром буфера 1, він насправді веде себе так само, як BehaviorSubject"


Це не зовсім вірно; перевірте цю чудову допис у блозі щодо відмінностей між цими двома. Наприклад, якщо ви підписалися на завершене BehaviorSubject, ви не отримаєте останнього значення, але для цього ReplaySubject(1)ви отримаєте останнє значення.

Це важлива відмінність, яку не слід випускати з уваги:

const behavior = new BehaviorSubject(null);
const replay = new ReplaySubject(1);

behavior.skip(1).subscribe(v => console.log('BehaviorSubject:', v));
replay.subscribe(v => console.log('ReplaySubject:', v));

behavior.next(1);
behavior.next(2);
behavior.complete();
behavior.subscribe(v => console.log('Late B subscriber:', v));

replay.next(1);
replay.next(2);
replay.complete();
replay.subscribe(v => console.log('Late R subscriber:', v));

Перевірте цей приклад коду тут , який виходить від іншого великого блозі на цю тему.


0
     // ***********Subject  concept ***********
    let subject = new Subject<string>();


    subject.next("Eureka");
    subject.subscribe((data) => {
      console.log("Subscriber 1 got data >>>>> "+ data);
    });
    subject.subscribe((data) => {
      console.log("Subscriber 2 got data >>>>> "+ data);
    });

       // ********behaviour subject*********
    // Behavior subjects need a first value
let subject1 = new BehaviorSubject<string>("First value");


subject1.asObservable().subscribe((data) => {
  console.log("First subscriber got data behaviour subject>>>>> "+ data);
});
subject1.next("Second value")
  • Тема - Абонент отримуватиме опубліковані значення лише після того, як буде зроблена підписка.
  • BehaviorSubject - Нові абоненти отримують останнє опубліковане значення АБО початкове значення відразу після підписки.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.