Каковы субъекты RxJS и преимущества их использования?

Я обнаружил, что документы RXJS определяют их как

Что такое предмет? Субъект RxJS - это особый тип Observable, который позволяет многоадресно передавать значения многим наблюдателям. В то время как простые Observables являются одноадресными (каждый подписанный Observer обладает независимым исполнением Observable), субъекты являются многоадресными.

и далее приводятся примеры, но я ищу базовое объяснение ELI5. Насколько я понимаю, это помогает обрабатывать и определять элементы в последовательности. Это верно?

Я думаю, что было бы очень полезно для меня и других увидеть простую функцию с и без определения субъекта rxJS, чтобы понять, почему это важно?

Спасибо!

4 ответа

Самый простой способ понять это - подумать о Subject как производитель, так и потребитель. Это как открытый канал, где кто-то может отправить сообщение на одном конце, а подписчики получат его на другом конце.

                                  +---------------
Sender                            | =>  =>  =>  =>  Subscriber
           -----------------------+   +----------- 
Message =>  =>  =>  =>  =>  =>  =>  =>  =>  =>  =>  Subscriber
           -----------------------+   +-----------
                                  | =>  =>  =>  =>  Subscriber
                                  +---------------

В терминах кода говорят, что у вас есть услуга с темой

class MessageService {
  private _messages = new Subject<Message>();

  get messages: Observable<Message> {
    return this._messages.asObservable();
  }

  sendMessage(message: Message) {
    this._messages.next(message);
  }
}

Обратите внимание messages получатель, возвращающий Предмет как Наблюдаемый. Это не обязательно. Subject уже наблюдаемый, и любой может подписаться непосредственно на Subject, Но я думаю, что asObservable шаблон используется как способ ограничения того, что пользователи могут с ним делать, то есть пользователи используют его только для подписки, а не для эмиссии. Мы сохраняем эмиссию для sendMessage метод.

Теперь, когда эта служба установлена, мы можем внедрить ее в разные компоненты, и это может стать способом взаимодействия двух (или более) произвольных компонентов (или просто получения уведомлений о произвольных событиях).

class ComponentOne {
  constructor(private messages: MessageService) {}

  onClick() {
    this.messages.sendMessage(new Message(..));
  }
}

class ComponentTwo {
  constructor(private messages: MessageService) {}

  ngOnInit() {
    this.messages.messages.subscribe((message: Message) => {
      this.message = message;
    });
  }
}

Собственный Angular EventEmitter на самом деле Subject, Когда мы подписываемся на EventEmitter мы подписываемся на Subject и когда мы emit на EventEmitter мы отправляем сообщение через Subject для всех подписчиков.

Субъекты полезны, когда код, в котором вы находитесь, является источником, который фактически создает наблюдаемые данные. Вы можете легко позволить своим потребителям подписаться на Subject а затем позвоните next() функция для передачи данных в конвейер.

Однако, если вы получаете данные из другого источника и просто передаете их (возможно, сначала преобразуете их), то вам, скорее всего, нужно использовать один из операторов создания, показанных здесь, например, Rx.Observable.fromEvent вот так:

var clicks = Rx.Observable.fromEvent(document, 'click');
clicks.subscribe(x => console.log(x));

Это позволяет вам оставаться в функциональной парадигме, в то время как использование SubjectНесмотря на то, что он имеет свое применение, некоторые считают запахом, что вы пытаетесь заставить императивный код в декларативную структуру.

Вот отличный ответ, который объясняет разницу в двух парадигмах.

Если вы хотите самое простое объяснение...

Наблюдаемые обычно являются результатом чего-то. Результат вызова http, и все, что вы делаете с каналом, возвращает наблюдаемое.

Но каков источник этих вещей? Вы когда-нибудь задумывались, как вы подключаете свои пользовательские события ко всей вещи rxjs? Главной особенностью предметов является то, что вы можете использовать метод next() для них.

При реактивном программировании первым шагом обычно является составление списка возможных предметов.

Например: допустим, мы должны создать приложение для списка задач. Вероятно, в нашем компоненте будет пара переменных:

public deleteItem$ = Subject<TodoItem> = new Subject();
public addItem$ = Subject<TodoItem> = new Subject();
public saveList$ = Subject<TodoItem[]> = new Subject();

и в нашем приложении мы подключим их так:

<button (click)="deleteItem$.next(item)">Delete</button>

Используя rxjs, мы будем использовать операторы, такие как merge/combLatest/withLatestFrom, чтобы обрабатывать эти темы и определять логику нашего приложения.

Я посмотрю, смогу ли я найти время, чтобы сделать небольшой пример.

Вы можете найти исследование семантики предметов здесь.

Все ответы, которые я вижу, верны. Я просто добавлю, что термин subject исходит из шаблона наблюдателя (см. https://en.wikipedia.org/wiki/Observer_pattern). Поскольку такой субъект является своего рода ретранслятором, он получает что-то на одном конце и испускает это на любом из своих концов (подписок).

Другие вопросы по тегам