Преобразование Observable<String[]> в Observable<DataType[]>

У меня есть API, который возвращает мне Array<string> идентификаторов с учетом исходного идентификатора (один ко многим). Мне нужно сделать http-запрос для каждого из этих идентификаторов, чтобы получить связанные данные из API. Я не могу понять, как взять Observable<string[]> и сопоставить его с Observable<DataType[]>.

Я хотел бы сохранить оригинал наблюдаемым и использовать операторы для получения желаемого результата, если это вообще возможно.

Конвейерная передача оператора map в этой ситуации не работает из-за того, что единственным элементом в наблюдаемом объекте является массив.

Вот пример кода, который похож на реализацию, которую я пытаюсь реализовать.

getIds = (originalId: string) => {
 return this.http.get<string[]>(url);
}

getDataFromIds = (originalId: string): Observable<DataType[]> => {
  const ids$ = this.getIds(originalId);
  // Make http calls for each of the items in the array.
  result = ids$.pipe();

  return result;
}

Грубо говоря, вы хотите сменить карту на forkJoin. Однако вы не описали, что должно произойти в случае сбоя одного из этих запросов.

Ingo Bürk 05.03.2019 18:29

Хорошая точка зрения. Я не думал о возможности сбоя http. Если запрос не выполнен, он должен просто перейти к следующему идентификатору, исключая неудачный ответ.

Buttars 05.03.2019 18:31
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
2
153
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете попробовать это:

ids$.pipe(
  switchMap(ids => //you can swap switchMap with any *Map operator: https://www.learnrxjs.io/operators/transformation/
    forkJoin(...ids.map(id => //you swap forkJoin with any comb. operator: https://www.learnrxjs.io/operators/combination/
      from(Promise.resolve({ id })).pipe(
        map(res => res.id),
        catchError(err => of(err)))))));

Импорт для from, forkJoin должен быть из rxjs, а все остальное импортируется из rxjs/operators

catchError будет ловить любые выброшенные ошибки необработанный.

Демо: https://stackblitz.com/edit/rxjs-xmmhyj

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

bryan60 05.03.2019 19:03

У forkJoin есть недостаток, который требует завершения наблюдаемого для распространения конечного результата, это может заблокировать поток, и вам действительно следует учитывать компромиссы при использовании различных операторов. Каждый случай индивидуален.

Zdravko Tatarski 05.03.2019 19:08

OP указал, что речь идет о http-вызовах, что означает, что они завершаются, и forkJoin является правильным оператором для этого варианта использования.

bryan60 05.03.2019 19:18
Ответ принят как подходящий

это вариант использования оператора switchMap, как правило, с оператором forkjoin в качестве вашего внутреннего наблюдаемого.

getIds = (originalId: string) => {
 return this.http.get<string[]>(url);
}

getDataFromIds = (originalId: string): Observable<DataType[]> => {
  const ids$ = this.getIds(originalId);
  // Make http calls for each of the items in the array.
  result = ids$.pipe(switchmap(ids => forkJoin(ids.map(id => this.getId(id))));
  // map the array of ids into an array of Observable<DataType>, forkjoin them and switch into it.

  return result;
}

Это предполагает, что вызов getIds() приведет к списку идентификаторов строк и что у вас есть некоторая функция getId(), которая принимает идентификатор строки и возвращает наблюдаемый тип данных.

Мы закончили с тем же результатом, за исключением того, что я использовал оператор combineAll(). Есть ли у моего метода недостатки перед forkJoin()?

Buttars 05.03.2019 21:03

В итоге получается то же самое в этом случае использования. Тонкая разница в том, что forkJoin будет выдавать только 1 значение: окончательный массив результатов после завершения всех внутренних наблюдаемых. combineAll может выдавать несколько значений: один раз, когда каждая из внутренних наблюдаемых производит значение, и снова, когда любая из внутренних наблюдаемых создает дополнительное значение. Поскольку ваши внутренние наблюдаемые объекты заканчиваются после 1 значения, это различие становится спорным. Я бы использовал forkJoin, потому что это кажется более семантически правильным.

Brandon 05.03.2019 21:34

Тот же результат здесь. Предпочла бы forkJoin, потому что обычно от combLatest ожидается, что внутренние потоки имеют несколько выбросов, тогда как forkJoin является декларативным, что вы ожидаете одиночный выброс.

bryan60 05.03.2019 21:40

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