Массив внутри объекта не определен после подписки

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

Получить функцию в моем сервисе:

get() {
return new Observable(project => {
  this.channelsService.get().subscribe(
    stations => {
      this._stations = stations;
      this._stations.forEach((station) => {
        station.cssClass = this.channelsService.getCss(station.id.split('/').pop());
        station.plstation$thumbnails = this.channelsService.getThumbnails(station.id.split('/').pop());
        if (station.plstation$callSign !== '') {
          const watchliveUrl = this.watchLiveApi + station.plstation$callSign + '/?schema=1.0.0';
          this.http.get(watchliveUrl).subscribe(data => {
            const body = data.json();
            station.currentListing = body.currentListing;
            station.nextListing = body.nextListing;
            project.next(stations);
            project.complete()
          });
        }
      });

    }, (error) => {
      this.mapErrorService.mapError(error, 'Listing service (1)');
    });
});

}

get() используется и подписывается:

 constructor(private listingService: ListingService) {
this.listingService.get().subscribe((stations) => {
  this.stripDetails.channelList = stations;
  // stations[6].currentListing Not undefined
  console.log(stations);
  // Now is undefined
  console.log(stations[6].currentListing);

});  }

Как определить станции[6].currentListing?


person goltornate    schedule 25.09.2017    source источник


Ответы (1)


Вы конвертируете Observable из http.get() в Promise, но ничего не делаете с этим Promise. Таким образом, хотя stations определено там, где вы говорите, Promise не будет завершено, поэтому атрибут currentListing будет неопределенным.

При использовании Observable или Promise вы всегда должны ждать результата. Итак, в этом случае, если вы хотите использовать промисы, вам нужно собрать их все вместе и не выводить project, пока они все не будут выполнены.

Что-то типа:

get() {
return new Observable(project => {
  this.channelsService.get().subscribe(
    stations => {
      this._stations = stations;
      let responses = this._stations.map((station) => {
        station.cssClass = this.channelsService.getCss(station.id.split('/').pop());
        station.plstation$thumbnails = this.channelsService.getThumbnails(station.id.split('/').pop());
        if (station.plstation$callSign !== '') {
          const watchliveUrl = this.watchLiveApi + station.plstation$callSign + '/?schema=1.0.0';
          return this.http.get(watchliveUrl).map(data => {
            const body = data.json();
            station.currentListing = body.currentListing;
            station.nextListing = body.nextListing;
          });
        }
      });
      // Wait for all requests to complete.
      Rx.Observable.forkJoin(...responses).subscribe(() => {
            project.next(stations);
            project.complete()
      });

    }, (error) => {
      this.mapErrorService.mapError(error, 'Listing service (1)');
    });
});
person Duncan    schedule 25.09.2017
comment
Проблема в том, что у вас есть цикл forEach, запускающий несколько запросов, и вы вызываете project.complete(), когда завершается первый из HTTP-запросов. Вы должны собрать все запросы вместе и выполнить project только после того, как все ответы будут получены. Вы можете использовать Rx.Observable.forkJoin() для этого. - person Duncan; 27.09.2017
comment
Где именно я должен поместить эту функцию? - person goltornate; 28.09.2017
comment
Я вставил, как я думаю, что это могло бы пойти, но я не совсем уверен здесь. Важно то, что вам нужно дождаться завершения всех запросов, которые вы делаете, вызывая forkJoin с массивом наблюдаемых. - person Duncan; 04.10.2017