Вопрос или проблема
У меня проблемы с цепочкой mergeMap для получения связанных объектов. Сначала я получаю список пользователей
userService.loadUsers$().pipe(
mergeMap((users: User[]) => forkJoin(users.map((user: IUser) =>
combineLatest([
getRelatedItems(user.uid || '')
])
Код выше получит всех желаемых пользователей, если я уберу getRelatedItems. getRelatedItems сначала смотрит в таблице/коллекции перекрестных ссылок, а затем должен вернуть связанные элементы.
const getRelatedItems = (uid: string) => referenceService.loadReferenceItems$({uid})
.pipe(mergeMap((referenceItems) => forkJoin(referenceItems.map((referenceItem) =>
relatedItemsService.getRelatedItem(referenceItem.relatedItemId || '')
))))
Код выше вызывается, но не возвращает никаких значений. Что я упускаю?
Судя по всему, mergeMap возвращает массив наблюдаемых объектов, он должен возвращать наблюдаемый объект. Вы можете сделать это forkJoin
, который оборачивает массив и выполняет внутренние наблюдаемые объекты параллельно.
getRelatedItems = (uid: string) =>
referenceService
.loadReferenceItems$({ uid })
.pipe(
mergeMap((referenceItems) =>
forkJoin( // <- изменено здесь!
referenceItems.map((referenceItem) =>
relatedItemsService.getRelatedItem(
referenceItem.relatedItemId || ''
)
)
)
)
);
Ответ или решение
Чтобы корректно объединить функции mergeMap
и получить сопоставленные объекты, необходимо учитывать особенности работы RxJS и правильно использовать операторы. Ниже представлен более детализированный подход к данной задаче, учитывающий все необходимые моменты.
Проблема
Вы сталкиваетесь с трудностями при цепочечном объединении операторов mergeMap
, когда хотите получить связанные объекты после загрузки пользователей. Ваш код успешно извлекает список пользователей, но при добавлении getRelatedItems
результат не возвращается. Это может происходить из-за того, что не все операции выполняются корректно или из-за того, что не получается возвратить необходимое значение.
Решение
Чтобы корректно связать вызовы и получить необходимые данные, следует учесть следующее:
-
Понимание
mergeMap
иforkJoin
:
ОператорmergeMap
позволяет развернуть Observable, генерируя новое значение для каждого элемента. Он возвращает новый Observable, который генерируется на основе результатов внутреннего Observable. Однако, когдаmergeMap
возвращает массив Observable (например, в результатеmap
), вам необходимо обернуть этот массив вforkJoin
, чтобы дожидаться завершения всех внутренних Observable и получить результат как единое значение. -
Корректная структура вашего кода:
ИспользуйтеforkJoin
правильно во всех местах, где возвращаете массив Observable. Также нужно следить за тем, чтобы каждый уровень возвращал Observable, чтобы имелась возможность дальнейшей работы с полученными данными.
Примерный код
Вот исправленный фрагмент кода, который должен работать, как вы ожидаете:
userService.loadUsers$().pipe(
mergeMap((users: User[]) =>
forkJoin(
users.map((user: IUser) =>
getRelatedItems(user.uid || '').pipe(
map(relatedItems => ({ user, relatedItems })) // связываем пользователя и его связанные элементы
)
)
)
)
).subscribe(result => {
console.log(result); // результат содержит массив пользователей с их связанными элементами
});
const getRelatedItems = (uid: string) =>
referenceService.loadReferenceItems$({ uid }).pipe(
mergeMap(referenceItems =>
forkJoin(
referenceItems.map(referenceItem =>
relatedItemsService.getRelatedItem(referenceItem.relatedItemId || '')
)
)
)
);
Подробное описание изменений
-
Добавление
map
внутриforkJoin
:
Внутри функцииmap
, которая вызывается над массивом пользователей, добавлен дополнительныйmap
, который связывает пользователей и их связанные элементы. Это значительно упрощает обработку данных после завершения всех асинхронных операций. -
Структура результатов:
Теперь результат подписки будет содержать массив объектов, где каждый объект — это пользователь, связанный со своими элементами. Это удобно для дальнейшей обработки данных. -
Использование
forkJoin
:
Обертывание вforkJoin
гарантирует, что вы получите массив результатов только после завершения всех соответствующих запросов. Это предотвращает ситуации, когда вы наблюдаете "пропадающие" значения.
Заключение
Следуя этим рекомендациям, вы сможете корректно объединить запросы и получить необходимые связанные данные. Хороший подход к организации кода, использование операторов RxJS в соответствии с их функционалом, а также тщательное оформление бизнес-логики помогут вам избежать проблем в будущем и обеспечить чистоту кода. Вы также можете оценить производительность и читаемость вашего кода, что в перспективе упростит его сопровождение и изменение.