Получение текущего значения RxJS Subject без подписки в Angular 2
Быстрый ответ
Чтобы мгновенно получить последнее значение из BehaviorSubject, употребите метод getValue(). Обычные объекты типа Subject не хранят значения внутри. Чтобы извлечь значение из Observable, преобразуйте его в BehaviorSubject, либо примените оператор take(1) для получения одного излучаемого значения:
// BehaviorSubject
const behaviorSubject = new BehaviorSubject('initial');
console.log(behaviorSubject.getValue()); // 'initial' — это удалось
// Observable
observable.pipe(take(1)).subscribe(console.log); // выведет первое излучаемое значение — и на этом мы закончим

Используем BehaviorSubject и метод getValue
Особенность BehaviorSubject заключается в том, что он сохраняет последнее значение и сразу же передает его новым подписчикам. Это идеально подходит для быстрого доступа к текущему состоянию при новой подписке.
// Создаем BehaviorSubject
const behaviorSubject = new BehaviorSubject('initial');
// Новая подписка тут же получает текущее значение
behaviorSubject.subscribe(value => console.log(value)); // 'initial', и можно приступать к работе
Метод getValue() позволяет непосредственно извлечь текущее значение без создания новой подписки. Этот метод особенно полезен, если вам необходимы синхронные данные.
ReplaySubject и shareReplay: наши помощники во времени
ReplaySubject может повторить ранее излучаемые значения для новых подписчиков. Оператор shareReplay() позволяет Observable работать в режиме мультикастинга, аналогично ReplaySubject, предоставляя прошлые события подписчикам сразу после подписки.
// ReplaySubject
const replaySubject = new ReplaySubject(3);
replaySubject.next(1);
replaySubject.next(2);
replaySubject.next(3);
replaySubject.subscribe(value => console.log(value)); // Выдаст 1, 2, 3... знакомые числа?
// shareReplay сместе с Observable
const sharedObservable = sourceObservable.pipe(shareReplay(1)); // Поделиться значит заботиться о других
Мультикастинг с использованием Subjects: согрейтесь!
Операторы publishReplay(), publishBehavior() и multicast() могут превратить холодные Observable в горячие мультисообщения и поделиться их теплом с несколькими подписчиками. Для запуска совместной трансляции следует использовать метод connect().
const source = interval(1000);
const connectableObservable = source.pipe(
publishReplay(1),
);
const subscription = connectableObservable.connect(); // И вот мы вышли на эфир!
Объединение Observables: сила синергии
Используйте withLatestFrom или combineLatest для объединения последних значений из нескольких Observables. При каждом излучении одного из объектов мы получаем массив последних значений от каждого Observable.
const priceTicker$ = new BehaviorSubject(100);
const quantityInput$ = new BehaviorSubject(1);
const totalCost$ = priceTicker$.pipe(
withLatestFrom(quantityInput$),
map(([price, quantity]) => price * quantity),
);
totalCost$.subscribe(console.log); // Стоимость всего содержимого... возьмите ваш заказ, пожалуйста
Превращение текущего значения в промис
Иногда требуется получить текущее значение, словно подавая его на блюдечке. В таком случае Observable можно преобразовать в Promise с помощью метода toPromise(), а затем дождаться получения значения в синхронном стиле. Однако такое превращение нам приходится тратить реактивность.
const currentValuePromise = observable.pipe(take(1)).toPromise();
const currentValue = await currentValuePromise; // И... поехали!
BehaviorSubject в роли менеджера состояния
В Angular часто используют объекты типа BehaviorSubject для передачи данных о состоянии приложения. Выставляя эти состояния в виде Observable, доступных только для чтения, мы обеспечиваем реактивный поток данных для компонентов. Главное правило — контролировать доступ к методу next() внутри сервиса.
// service.ts
private state = new BehaviorSubject<MyState>(initialState);
state$ = this.state.asObservable();
setState(newState: MyState): void {
this.state.next(newState); // Мы можем менять состояния также просто, как перелистываем страницы
}
// component.ts
this.service.state$.subscribe(state => console.log(state)); // Ждем актуальных данных
Фильтр и First — ваша защита от лишнего
Использование filter() вместе с first() помогает вам гарантировать излучение только значений, удовлетворяющих условиям, и завершает подписку после встречи с первым успешным событием.
observable.pipe(
filter(value => value != null), // Только значимые данные
first(), // Единственное событие — и исчезаем!
).subscribe(console.log); // Вот и условное значение!
Практические советы
- Избавьтесь от привычки часто использовать метод
getValue(), чтобы оставаться верным идеям реактивного программирования RxJS. - Используйте
BehaviorSubjectиReplaySubjectнаиболее эффективно в соответствии с требованиями вашего приложения. - Грамотный выбор типа Subject в RxJS и подходящего оператора может значительно усовершенствовать архитектуру вашего приложения.
- Отдавайте предпочтение
combineLatestиwithLatestFromдля совместной передачи данных вместо громоздких цепочек вызовов. - Обновляйте
BehaviorSubjectс помощью методаnext()в сервисах для отражения изменений в реальном времени у всех подписчиков.
Визуализация
Представьте себе радио (📻) с большим числом закодированных станций (Observables):
| Радиостанция (Observable) | 📻 |
|---|---|
| Станция А | 🎵 |
| Станция B | 🎶 |
| Станция C | 🔊* |
| Станция D | 🎼 |
Как же узнать, какую песню сейчас играют? Специальные наушники (.getValue() для Subject) позволяют подключаться к текущему эфиру:
const currentTune = subject.getValue(); // 🔊👂* Мы слушаем горячий хит от станции C
В чем особенность этих наушников? Они позволяют услышать текущую песню прямо сейчас, без необходимости ждать следующую.
Рекомендации по безопасности
Не стоит слишком увлекаться функцией getValue(). Ее преимущества могут помешать вам придерживаться реактивных принципов. Стремитесь поддерживать реактивные потоки данных, чтобы приложение было более понятным и, следовательно, более подконтрольным.
Не забываем про отписку при использовании объектов типа BehaviorSubject и ReplaySubject для предотвращения потенциальных утечек памяти. Для элегантного контроля подписок используйте метод pipe в компании с оператором takeUntil.
Мастерство работы с мультикастингом
Для более тонкого управления мультикастингом попробуйте комбинацию RefCount c publishReplay() или publishBehavior(). Такой подход гарантирует, что обмен данными начинается только тогда, когда есть хотя бы один подписчик, и прекращается при их полном отсутствии.
Раздумья об архитектуре
Выбор между объектами типа Subjects и Observables будет определять реактивную архитектуру вашего приложения. Отражает ли она реальную динамику взаимодействия между компонентами, между источниками и потребителями данных?
Полезные материалы
- GitHub – ReactiveX/rxjs – Исходный код RxJS для изучения и внесения вклада в библиотеку.
- RxJS Официальная документация – Руководство по Subjects, включая
BehaviorSubject. - ReactiveX – Операторы – Детальное описание разнообразных операторов RxJS.
- Stack Overflow – Разница между BehaviorSubject и Observable – Обсуждение различий между
BehaviorSubjectиObservable. - Hot vs Cold Observables – автор Ben Lesh | Medium – Статья Бена Леша о горячих и холодных объектах Observable.
- BehaviorSubject – Учим RxJS – Руководство и примеры использования объектов типа
BehaviorSubject. - Понимание Behavior, Replay и Async Subject в RxJS – YouTube – Видеообзор, посвященный особенностям
BehaviorSubject,ReplaySubjectиAsyncSubject.


