#angular #rxjs #ngrx
#angular #rxjs #ngrx
Вопрос:
В моем приложении Angular6 у меня есть эффект, который сначала получает идентификаторы пользователей, а затем выполняет 2 вызова API для каждого идентификатора: getName и getAge. В идеале я хотел бы, чтобы полученные данные были сгруппированы по идентификаторам: сначала данные для первого идентификатора, затем для второго и так далее. Пример: [ [Анна, 18], [Макс, 22] ].
Как этого добиться? Я думал, что zip-оператор может помочь, но не может найти правильный способ. С этим кодом ниже вызовы API не выполняются, хотя точка останова попадает в обе функции, которые выполняют вызовы.
@Effect()
loadAllNames$: Observable<Action> = this.actions$.ofType(allUsersActions.LOAD_ALL_NAMES)
.pipe(
concatMap(action => {
return this.apiService.getUserIds()
}),
switchMap(ids => { // [ 3423, 1222, 43234, 1232];
let observableBatch = ids.map(id => {
this.apiService.getName(id), // brekpoint hits this fn
this.apiService.getAge(id) // brekpoint hits this fn
})
return zip(observableBatch)
.pipe(
switchMap((res) => {
this.store.dispatch(new allUsersActions.SetAllUsers(res));
return of(
new spinnerActions.HideSpinner()
)
}),
catchError(error => of(new spinnerActions.HideSpinner()))
)
})
)
Служба API:
public getName(id): Observable<any> {
return this.http.get<any[]>(URL id)
}
Комментарии:
1. Каково содержимое console.log(observableBatch)? У вас есть this.apiService.getAge, также определенный рядом с getName в вашем сервисе, верно?
2. @Adam , я не знаю почему, но console.log(observableBatch) возвращает массив
undefined
. Однако функции в службе api получают правильные идентификаторы. И да,getAge()
также существует в службе.
Ответ №1:
Это просто внутренний, switchMap
который будет принимать один id
за другим и запускать оба вызова одновременно.
...
switchMap(ids => from(ids).pipe(
concatMap(id => forkJoin(
this.apiService.getName(id),
this.apiService.getAge(id),
)),
toArray(),
)),
Живая демонстрация:https://stackblitz.com/edit/rxjs-85y3bv
Комментарии:
1. эти запросы будут последовательными при такой реализации. лучше сделать их параллельными
2. @Andrey что вы подразумеваете под «эти запросы будут последовательными»? И каков правильный способ, по вашему мнению? Спасибо
3.
concatMap
заставляет ваши запросы отправляться один за другим, а не параллельно. Я бы сказал, что правильным способом было быof(ids).pipe(switchMap((ids) => forkJoin(ids.map(id => forkJoin(this.apiService.getName(id),this.apiService.getAge(id))))))