RXJS: объединение результатов нескольких вызовов конечных точек в один массив

#typescript #rxjs #nestjs

#typescript #rxjs #nestjs

Вопрос:

У меня есть конвейер RXJS, похожий на этот:

 const logs: number[] = [1, 2, 3, 4];
const url = 'http://some-url-here.com';

const pipeline = from(logs).pipe(
  switchMap(logId =>
    this.callEndpoint(url, logId).pipe(map(response => response.data)),
  ),
);

const res = await pipeline.toPromise();
console.log(res);



// The real function uses nestJS http service to call a url
callEndpoint(url: string, logId: number) {
  const result = Math.random() * 1000;
  console.log(`result in callEndpoint: ${result}`);
  return of({ data: result });
}
 

вот пример вывода кода:

 result in callEndpoint: 586.773956063481
result in callEndpoint: 842.136341622411
result in callEndpoint: 964.0849490798163
result in callEndpoint: 598.7596176858414
598.7596176858414
 

Последнее число является результатом res .

Как мне получить объединенные результаты всех успешных вызовов конечных точек в один массив res ?

Ответ №1:

Используйте forkJoin , если вы хотите отправить все запросы сразу или concat с toArray , чтобы отправлять запросы последовательно и собирать результаты в массив. Вероятно, вы захотите добавить обработку ошибок catchError и вернуть наблюдаемое значение, которое в этом случае не вызывает ошибок.

 const getData = (logId) => this.callEndpoint(url, logId).pipe(
  map(response => response.data),
  catchError(error => of(null))
)
const requests = logs.map(logId => getData(logId));

// parallel requests
forkJoin(requests).subscribe(res => console.log(res));

// sequential requests
concat(...requests).pipe(toArray()).subscribe(res => console.log(res));
 

res будет представлять собой массив, который может содержать null значения в случае сбоя запроса.
При сбое второго запроса это может выглядеть так:

 [586.773956063481, null, 964.0849490798163, 598.7596176858414]
 

Ответ №2:

Вы можете использовать toArray() для сбора всех выбросов и выделения их в виде одного массива после завершения исходной наблюдаемой.

 const pipeline = from(logs).pipe(
  switchMap(logId =>
    this.callEndpoint(url, logId).pipe(map(response => response.data)),
  ),
  toArray(),
);
 

Тем не менее, я думаю, что вы не хотите использовать switchMap в этом случае, потому что наблюдаемый здесь источник from() — это то, что сразу же отправит все элементы logs и switchMap сохранит подписку только на последний. Поэтому вы можете использовать concatMap вместо этого.