Angular 2: Цепные наблюдаемые в Resolver

Я новичок в 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, ...). Основная причина была в том, что я просто не понял их функциональный аспект. Я призываю людей в одной лодке взглянуть на эту прекрасную серию статей о функциональном программировании Чарльза Скальфани.

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

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