Angular 2: цепные наблюдаемые в резольвере

Я новичок в Angular2 и наблюдаемых. Я пытаюсь вернуть результат цепочки наблюдаемых моему преобразователю и не могу найти ответ на SO. Все работает нормально, когда я возвращаю только один наблюдаемый, но не работает, когда они связаны. Я упростил код, чтобы дважды последовательно вызывать одну и ту же тестовую функцию:

@Injectable()
export class SwResolve implements Resolve<any> {
    constructor(private swService: SwService) {}    
        resolve (route: ActivatedRouteSnapshot): Observable<MyObject> | Promise<any> | any {
             this.swService.getTestData().subscribe(data => {
                 return this.swService.getTestData();
             });
        }
}

SwComponent:

export class SwComponent implements OnInit {constructor(
    private route: ActivatedRoute,
    private router: Router
  ) { }

  ngOnInit(): void {
    this.route.data.forEach((data: any) => {
      // Handle data received
     });
  }
};

SwService:

  getTestData() {
    return Observable.create(observer => {
      let testObject : SwDataObject = {
        'labels':['value0','value1'],
        'desktop':[123,456],
        'mobile':[789,1011]
      };
      observer.next(testObject);
      observer.complete();
    });
  }

Что я здесь делаю не так?

Спасибо !

Изменить 17 июня: добавление дополнительной информации, так как мне потребовалось время, чтобы обернуть голову вокруг методов RxJs (flatMap, mergeMap, ...). Основная причина заключалась в том, что я просто не понимал их функционального аспекта. Я призываю людей в одной лодке взглянуть на прекрасная серия статей по функциональному программированию Чарльза Скалфани.


person Standaa - Remember Monica    schedule 25.10.2016    source источник


Ответы (1)


Функция разрешения ожидает возврата наблюдаемого. То, что вы делаете, неверно, поскольку вы возвращаете только асинхронный результат. Вы вызываете первую наблюдаемую, а затем подписываетесь на нее. Итак, время идет, и только если первая наблюдаемая разрешена, вы возвращаете наблюдаемую.

То, что вы должны использовать для подобных вещей (которые имеют поведение, аналогичное Promise.then (вроде)), - это flatMap / mergeMap (псевдонимы в RxJS5).

Реорганизуйте свой код так:

@Injectable()
export class SwResolve implements Resolve<any> {
    constructor(private swService: SwService) {}    
        resolve (route: ActivatedRouteSnapshot): Observable<MyObject> | Promise<any> | any {
             return this.swService.getTestData().mergeMap(data => 
                 return this.swService.getTestData();
             );
        }
}

Это будет немедленно возвращать наблюдаемое.

Что делает mergeMap, так это получает событие в качестве входных данных (в данном случае результат вашего первого вызова getTestData ()) и ожидает, что вы вернете другой наблюдаемый объект. Под капотом он будет подписываться на эту наблюдаемую и сгладить результат.

На mergeMap есть масса статей, поэтому, если это неясно, я предлагаю вам прочитать несколько. Вот хорошее начало: https://github.com/btroncone/learn-rxjs/blob/master/operators/transformation/mergemap.md

person KwintenP    schedule 25.10.2016
comment
@KwibtenP Спасибо, по какой-то причине думал, что mergeMap и flatMap являются эксклюзивными для HTTP-вызовов. Код теперь возвращает другую ошибку: TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined - person Standaa - Remember Monica; 26.10.2016
comment
Можете выложить код у вас есть банкомат. Я вижу, что пропустил оператор возврата в своем ответе в mergeMap. Я обновил его (см. Ответ выше). Не могли бы вы попробовать, если это поможет. - person KwintenP; 26.10.2016
comment
Спасибо KwintenP, с обновленной версией работает! - person Standaa - Remember Monica; 26.10.2016