RxJS - сопоставить испущенное значение с комбинированным выводом нескольких запросов Http - PullRequest
0 голосов
/ 18 января 2019

У меня есть что-то вроде этого:

// getNums returns of Obsevable<number[]>
nums : Observable<number[]> = getNums();

// requestNum is a server call that takes a number and returns Observable<number>
serverNums : Observable<Observable<number>[]> = x.pipe(
    map(num_array => num_array.map(n => requestNum(n)))
);

// Part of an external API that I don't own.
function requestNum(num : number) : Observable<number> {
  // make a server call
}

Проблема в том, что serverNums имеет тип Observable<Observable<number>[]>.Мне нужно, чтобы serverNums было Observable<number[]>, поэтому я могу сделать

this.result = combineLatest(nums, serverNums).pipe(
    [nums : number[], serverNums : number[]] => {
      for (i=0; i<nums.length; i++) {
        console.log(nums[i], serverNums[i]);
      }
    }
);

, потому что this.result должен быть создан в моем конструкторе как тип Observable<Result[]>, а не установлен в подписке.

Так что я не могу сделать subscribe(() => {this.result = result}).

Ответы [ 2 ]

0 голосов
/ 19 января 2019

Используйте forkJoin , чтобы выполнить и объединить все ваши http-запросы и mergeMap массив, отправленный из вашего источника в Observable, возвращаемый forkJoin. forkJoin объединит последние (и только) переданные значения из всех ваших http-запросов в массив после того, как все они будут выполнены. Обратите внимание, что requestNum должен завершиться после выдачи значения для forkJoin для работы. (Http-запрос от Angular HttpClient завершается после того, как они передают значение)

В зависимости от вашей наблюдаемой x и желаемого поведения вы можете использовать switchMap вместо mergeMap.

import { forkJoin } from 'rxjs'; 
import { mergeMap } from 'rxjs/operators';

serverNums : Observable<number[]> = x.pipe(
    mergeMap(num_array => forkJoin(num_array.map(n => requestNum(n))))
);
0 голосов
/ 19 января 2019

Вы не объяснили, какова структура интерфейса данных, поэтому я могу предположить, что из массива:

[1,2,3]

Вы хотите создать объект:

{1:1, 2:2, 3:3}.

(если вы разместите ваш интерфейс данных, я обновлю ответ соответствующим образом).


Для создания объекта из массива вы можете использовать уменьшить :

x.pipe(reduce((pre,curr)=>{pre[curr]=curr; return pre;}, {})

Пипсы начинаются с пустого объекта ({}) и в каждой итерации добавляет свойство pre [curr] к этому объекту и задает ему значение curr.

  • pre - предыдущее значение из последней итерации
  • curr - текущее значение текущей итерации (1, 2 или 3 в приведенном выше примере)

EDIT:

Вам нужно выровнять Observable<Observable<number>> до Observable<number>, используя mergeMap (AKA flatMap):

serverNums : Observable<Observable<number>[]> = x.pipe(
    map(num_array => num_array.map(n => requestNum(n)),
    mergeMap(num=>num)
)

это выдаст все значения requestNum (n) в одной наблюдаемой типа Observable.

...