JavaScript 📜
March 21

Subject в RxJS

Перед тем как начать, для понимания этой статьи освежим знания по Rx. Допустим, у нас есть два Observable:

const interval$ = Rx.Observable.interval(1000);

interval$.subscribe(console.log);

setTimeout(() => {
  interval$.subscribe(console.log);
}, 2000);

Каждый раз, когда мы вызываем Subscribe с новым наблюдателем, мы создаем новое подписку. Можно представить это как обычную функцию, которая выполняется дважды. Например:

function interval() {
  setInterval(() => console.log('..'), 1000);
}

interval();

setTimeout(() => {
  interval();
}, 2000);


Мы создаем два interval(), которые независимы друг от друга. Но что, если нам нужно, чтобы второй наблюдатель получал те же события, что и первый?

Это случай, когда вам придется использовать Subject в Rx.

Что такое Subject?

Subject одновременно является как наблюдаемым объектом (Observable), так и наблюдателем (Observer).

  1. Наблюдатель (Observable) — имеет методы next, error и complete.
  2. Наблюдаемый объект (Observer) — имеет все операторы наблюдаемого объекта, и его можно подписать на него.

Subject может выступать в качестве моста/прокси между исходным наблюдаемым объектом и несколькими наблюдателями, что позволяет нескольким наблюдателям использовать один и тот же выполненный наблюдаемый объект.

Давайте посмотрим, как мы можем использовать одинаковое выполнение в нашем первом примере:

const interval$ = Rx.Observable.interval(1000);
const subject = new Rx.Subject();
interval$.subscribe(subject);


Для начала мы создадим новый Subject. Ранее уже проговорили, что Subject также является наблюдателем (observer). У всех наблюдателей присутствуют методы next(), error() и complete(). Их можно увидеть в консоли:


Итак, в нашем случае Subject наблюдает за Observable:

subject.subscribe(val => console.log(`First observer ${val}`));

setTimeout(() => {
  subject.subscribe(val => console.log(`Second observer ${val}`))
}, 2000);

Subjectтакже является наблюдаемым объектом (Observable), поэтому на него можно подписаться.

Если вы помните, что субъект наблюдает за интервальным наблюдаемым объектом, то каждый раз, когда интервал отправляет значения субъекту, субъект отправляет эти значения всем своим наблюдателям. В результате получилась реактивная реализация паттерна "посредник".

Рассмотрим другой пример:

const input = document.querySelector('input[type=text]');
const p = document.querySelector('p');

input.addEventListener('input', event => {
  subject.next(event.target.value);
});

subject.subscribe(val => {
  p.textContent = val;
});


Мы можем подписаться на Subject и вручную вызвать метод next(). Когда вы вызываете метод next(), каждый подписчик получит это значение.

Это перевод оригинального материала