Как сгенерировать последовательность наблюдаемых из наблюдаемой, которая генерирует массив

#javascript #typescript #rxjs

#javascript #машинописный текст #rxjs

Вопрос:

У меня есть массив наблюдаемых, для простоты я создаю образец массива ниже

  dataList = of([Array(20).fill(0).map((_r,k) => k)]); // of([1, 2, 3, 4, ..., 20])
 

Приведенное выше генерирует Observable объект, который генерирует массив. В реальном коде эти данные извлекаются с помощью http-вызова

Теперь я пытаюсь добиться этого;

  1. Для каждого из этого списка создайте новый Observable , который выдает каждый элемент за другим

Этого я добиваюсь с помощью flatMap оператора, как показано ниже

   flatMap(item => item )
 
  1. Сделайте http-запрос. Для этого я использую
   mergeMap(i => this.myService.save(i))
 
  1. Убедитесь, что каждый запрос запускается только после последнего запроса

вот тут-то у меня и возникла проблема

Из этой демонстрации я высмеял http запрос на возврат через 1 секунду. С консоли все это возвращается через 1 секунду. Но я бы хотел, чтобы это было что-то вроде

http /1
http / 2 (отложено до http/1 завершения)
http / 3 (отложено до http/2 завершения)
http / 4 (отложено до http/3 завершения)

http / 20 (отложено до http/19 завершения)

Комментарии:

1. Используйте concatMap вместо mergeMap . Вы также можете использовать from вместо of() в этом случае и избавиться от flatMap(item => item)

2. @мартин concatMap сработал! Потому что изменение of на from может быть не тем, что я ищу, но изменение mergeMap на concatMap сделало именно то, что я искал

Ответ №1:

Вероятно, это то, что вам нужно:

 of(Array(20).keys()).pipe(
  mergeMap(list => list),
  concatMap(i => this.myService.save(i))
)
 

Ниже приведен еще один способ сделать то же самое, хотя это может сделать идиоматическую проблему немного более понятной:

 of(Array(20).keys()).pipe(
  mergeMap(list => list.map(
    i => this.myService.save(i)
  )),
  concatAll()
)
 

concatMap и concatAll храните запросы буферизации (противодавления) в массиве, поэтому немного странно превращать массив в поток, а затем сразу же превращать этот поток обратно в массив.

Следующий подход пропускает этот шаг, сохраняя ваш массив целым и используя статический concat оператор (который принимает массив наблюдаемых вместо потока).

 of(Array(20).keys()).pipe(
  map(list => list.map(
    i => this.myService.save(i))
  ),
  switchMap(httpList => concat(...httpList))
)
 

которые могут быть объединены в один оператор следующим образом:

 of(Array(20).keys()).pipe(
  switchMap(list => 
    concat(...list.map(
      i => this.myService.save(i)
    ))
  ),
)