Hack Frontend Community

Что такое Subject и какие виды Subject’ов существуют в RxJS?

Что такое Subject в RxJS?

Subject — это особый тип Observable, который может мультикастить данные: т.е. отправлять значения сразу нескольким подписчикам.

Он объединяет свойства Observable (выдаёт значения) и Observer (можно передавать значения с помощью .next()).

Особенности

  • Вы сами инициируете передачу значений через .next()
  • Подписчики получают одинаковые данные
  • Позволяет централизованно управлять потоком событий

Пример использования обычного Subject

import { Subject } from 'rxjs';

const subject = new Subject<string>();

subject.subscribe(val => console.log('Подписчик A:', val));
subject.subscribe(val => console.log('Подписчик B:', val));

subject.next('Привет'); 
// → Подписчик A: Привет
// → Подписчик B: Привет

Виды Subject’ов

RxJS предоставляет несколько видов Subject’ов, которые отличаются по поведению и способу хранения значений:

ТипСохраняет значение?Что получает новый подписчик
SubjectНетТолько новые значения после подписки
BehaviorSubjectДа (только последнее)Сразу получает последнее значение
ReplaySubjectДа (все или часть)Получает все/несколько прошлых значений
AsyncSubjectДа (только финальное)Получает только последнее, когда complete()

BehaviorSubject

Используется, когда нужно, чтобы подписчики получали текущее значение сразу при подписке.

import { BehaviorSubject } from 'rxjs';

const behavior$ = new BehaviorSubject<number>(0);

behavior$.subscribe(val => console.log('A:', val)); // A: 0
behavior$.next(1); // A: 1
behavior$.subscribe(val => console.log('B:', val)); // B: 1

Идеально для хранения состояния (например, текущий пользователь, тема приложения и т.д.)

ReplaySubject

Позволяет «переиграть» прошлые значения для новых подписчиков.

import { ReplaySubject } from 'rxjs';

const replay$ = new ReplaySubject<number>(2); // хранит 2 последних значения

replay$.next(1);
replay$.next(2);
replay$.next(3);

replay$.subscribe(val => console.log('Подписчик:', val));
// → Подписчик: 2
// → Подписчик: 3

AsyncSubject

Выдаёт только последнее значение — только когда поток завершён (complete())

import { AsyncSubject } from 'rxjs';

const async$ = new AsyncSubject<number>();

async$.subscribe(val => console.log('Результат:', val));

async$.next(1);
async$.next(2);
async$.next(3);

async$.complete(); // → Результат: 3

Используется для отложенных значений, например, при однократном запросе данных

Когда использовать какой?

СценарийSubject
Поток событий (например, кнопки)Subject
Хранение состоянияBehaviorSubject
История сообщений или логовReplaySubject
Только результат после завершения операцииAsyncSubject

Совет:

В Angular чаще всего используют BehaviorSubject для управления состоянием компонентов и сервисов, так как он гарантирует актуальное значение при подписке.