Тема vs BehaviorSubject vs ReplaySubject в Angular


124

Я хотел понять эти 3:

Предмет , поведение субъект и субъект Replay . Я хотел бы использовать их и знать, когда и почему, каковы преимущества их использования, и хотя я читал документацию, смотрел учебные пособия и искал в Google, я не смог понять этого.

Так в чем их цель? Было бы очень полезно использовать реальный случай, который не требует даже кодирования.

Я бы предпочел чистое объяснение, а не просто «a + b => c, на которое вы подписаны ....»

Спасибо


1
Уже есть вопрос с предметом поведения с наблюдаемым; stackoverflow.com/questions/39494058/… и документация по теме воспроизведения ясна imo github.com/Reactive-Extensions/RxJS/blob/master/doc/api/…
eko

В этом ответе есть относительно подробное представление предметов в Rxjs , которое хорошо дополняет ответ от peeksilet. Сюда также входят важные сведения о поведении после завершения, так что неплохо бы посмотреть.
user3743222

Ответы:


278

Это действительно сводится к поведению и семантике. С

  • Subject- подписчик получит только опубликованные значения, которые были отправлены после подписки. Спросите себя, этого ли вы хотите? Нужно ли подписчику что-нибудь знать о предыдущих значениях? Если нет, то вы можете использовать это, в противном случае выберите один из других. Например, при межкомпонентной коммуникации. Допустим, у вас есть компонент, который публикует события для других компонентов по нажатию кнопки. Вы можете использовать сервис с предметом для общения.

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

    BehaviorSubjectИнициализируется с начальным значением. Иногда это важно для предпочтения кодирования. Скажем, например, вы инициализируете его с помощью null. Затем в вашей подписке вам нужно выполнить нулевую проверку. Может быть, ОК, а может, надоедает.

  • ReplaySubject- он может кэшировать до определенного количества выбросов. Все подписчики получат все кешированные значения при подписке. Когда вам понадобится такое поведение? Честно говоря, в таком поведении мне не было нужды, кроме следующего случая:

    Если вы инициализируете a ReplaySubjectс размером буфера 1, тогда он фактически ведет себя так же, как BehaviorSubject. Последнее значение всегда кэшируется, поэтому оно действует как значение, меняющееся со временем. При этом нет необходимости в nullпроверке, как в случае BehaviorSubjectинициализации с помощью null. В этом случае подписчику не передается никакого значения до первой публикации.

Так что на самом деле все сводится к ожидаемому поведению (в отношении того, какой из них использовать). В большинстве случаев вы, вероятно, захотите использовать, BehaviorSubjectпотому что то, что вы действительно хотите представить, - это семантика «значения во времени». Но лично я не вижу ничего плохого в замене ReplaySubjectinitialized на 1.

Чего вы хотите избежать, так это использования ванили, Subjectкогда вам действительно нужно какое-то кеширование. Возьмем, к примеру, вы пишете охраннику маршрута или решение. Вы получаете некоторые данные в этом страже и устанавливаете их в сервисе Subject. Затем в маршрутизируемом компоненте вы подписываетесь на субъект службы, чтобы попытаться получить то значение, которое было отправлено в Guard. Упс. Где ценность? Он уже был отправлен, DUH. Используйте тему "кеширование"!

Смотрите также:


1
Это коротко и легко понять различия. Когда значение изменяется в сервисе и компоненты также меняются, значение отображается, тогда решением будет BehaviourSubjects или Replay Subject.
Сайяфф Фарук,

1
Спасибо! ReplaySubjectс размером буфера 1 было именно то, что мне нужно. У меня был охранник маршрута, которому нужно было значение, но нужно было дождаться первого выброса. Таким образом, a BehaviorSubjectне сокращал его, так как мне не нужно было начальное значение ( nullтоже не сработало бы, потому что я использовал его для обозначения состояния)
menehune23

1
@ menehune23 Мне также нужен ReplaySubject для resolveкласса защиты Angular . Моя служба данных может быть асинхронной или синхронной (если данные уже были получены). Если это было синхронно, Subject.next () запускался до того, как resolveфункция была возвращена и на нее была подписана внутренняя подписка Angular. BehaviourSubject, возможно, сработает, но мне придется явно вызывать, complete()а также добавлять nullпроверки для начального значения. То , что сработало было новым ReplaySubject<DataType>(1) иresolveSubject.asObservable().take(1).map(....)
Drenai

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

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

16

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

  • Subject - Подписчик получит только опубликованные значения после того, как подписка будет сделана.
  • BehaviorSubject - Новые подписчики получают последнее опубликованное значение ИЛИ начальное значение сразу после подписки.
  • ReplaySubject - Новые подписчики получают все ранее опубликованные значения сразу после подписки

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

@JasonCheng нет, он извлекает все ранее опубликованные значения при подписке, обновите ответ :)
Рики Бойс,

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». :

Предмет является объектом, это турбированный наблюдаемым. По своей сути субъект действует так же, как обычный наблюдаемый объект, но каждая подписка привязана к одному и тому же источнику. Субъекты также являются наблюдателями и имеют методы next, error и done для одновременной отправки данных всем подписчикам. Поскольку субъекты являются наблюдателями, их можно передать непосредственно в вызов подписки, и все события из исходного наблюдаемого будут отправлены через субъект его подписчикам.

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

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


1

Самый популярный ответ явно неверен, утверждая, что:

"Если вы инициализируете a ReplaySubjectс размером буфера 1, тогда он фактически ведет себя так же, как BehaviorSubject"


Это не совсем так; проверьте это отличное сообщение в блоге о различиях между этими двумя. Например, если вы подпишетесь на завершенный BehaviorSubject, вы не получите последнее значение, но для a 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.