Angular / RxJS Multicasting Observable of Observable - PullRequest
0 голосов
/ 15 января 2019

У меня есть HTTP-запрос, который я хочу поделиться результатами для нескольких компонентов. HTTP-запрос, конечно, возвращает Observable. Я хочу, чтобы на несколько компонентов можно было подписаться без дополнительных HTTP-запросов.

Я выполнил это с помощью Subject в компоненте, который сделал HTTP-запрос по требованию и у которого есть другой способ подписки на тему. Хотя это работает - это кажется излишним, и, безусловно, есть лучший способ сделать это.

предметная служба

@Injectable()
export class EventService {
    subject: BehaviorSubject<any> = new BehaviorSubject<any>(Observable.create());

    constructor(private api: Api) {}

    fetch = () => {
        this.subject.next(
            this.api.getUsers().pipe(share())
        );
    };

    listen = (): Observable<any> => {
        return this.subject.asObservable();
    };
}

и один подписчик

@Injectable
export class EventListenerA {
    constructor(private eventService: EventService){
        eventService.fetch(); // make initial call
        eventService.listen().subscribe(o => {
             o.subscribe(httpResponse => {
                 //do something with response
             })
        });
    }
}

и второй абонент

@Injectable
export class EventListenerB {
    constructor(private eventService: EventService){
        eventService.listen().subscribe(o => {
             o.subscribe(httpResponse => {
                 //do something else with response
             })
        });
    }
}

Когда я удаляю share() из цепочки каналов, выполняется несколько сетевых запросов. Есть ли более элегантный / правильный способ передачи наблюдаемого в next из Subject? Или другой шаблон в целом

1 Ответ

0 голосов
/ 15 января 2019

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

Нет необходимости передавать HTTP, наблюдаемый с другими компонентами. Просто подпишитесь на HTTP-запрос и отправьте значение на ReplaySubject(). Любые компоненты прослушивания получат данные.

@Injectable()
export class EventService {
     private _events: ReplaySubject<any> = new ReplaySubject(1);

     public constructor(private _api: ApiService) {}

     public fetch() {
         this.api.getUsers().subscribe(value => this._events.next(value));
     }

     public listen() {
         return this._events.asObservable();
     }
 }

 @Injectable
 export class EventListenerA {
     constructor(private eventService: EventService){
          eventService.fetch();
          eventService.listen().subscribe(o => {
              // prints user data
              console.log(o); 
          });
     }
}

Каждый раз, когда кто-то звонит eventService.fetch(), он запускает HTTP-запрос. Если вы хотите выполнить этот запрос один раз, то, возможно, вызовите fetch() из конструктора службы или другого места в приложении, которое происходит только один раз (то есть конструктор модуля).

...