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