Угловые уровни RxJ повышаются во время зацикливания массива - PullRequest
1 голос
/ 25 марта 2019

У меня есть запрос http get для получения массива, подобного

[
  {name: 'name1', id: 1, specialProp: [] },
  {name: 'name2', id: 2, specialProp: [] }
]

Мне нужно получить каждый из элементов массива, взять идентификатор и отправить запрос на сервер, чтобы получить некоторую информацию.Результаты должны быть записаны в свойство specialProp.После этого мне нужно взять массив реквизита specialProp и для каждого элемента получить некоторые данные, поместить его в anotherSpecialProp.В конце концов у меня должен быть окончательный массив типа

[
  {name: 'name1', id: 1, specialProp: [
    {name: 'c', anotherSpecialProp: []}, 
    {name: 'd', anotherSpecialProp: []}
  ]},

  {name: 'name2', id: 2, specialProp: [
    {name: 'a', anotherSpecialProp: []},
    {name: 'b', anotherSpecialProp: []}
  ]}
]

У меня есть код:

this.http.get(url)
  .pipe(
    switchMap((mainItemArr: any) => from(mainItemArr)),
    mergeMap((mainItem: any): any => {
      return this.getSomeInfo(mainItem.Id) //another http get request
        .pipe(
          map((data: any): any => {
            return Object.assign(mainItem, { specialProp: data })
          }),
          switchMap((mainItemArr: any): any => from(mainItemArr.specialProp)),
          concatMap((item: any): any => {
            return this.getSomeOtherInfo(item.Id) // one more http get request
              .pipe(
                map((data: any): any => Object.assign({}, task, { anotherSpecialProp: data }))
              )
          }),
        )
    })
  )

Так что при подписке я получаю только элементы, а не весь mainItemArr.Может кто-нибудь помочь мне с этой проблемой? :)

Ответы [ 2 ]

3 голосов
/ 26 марта 2019

Если я правильно понял, вам нужно сделать следующее:

  • получить исходный массив из серверной части
  • для каждого элемента массива вызовите getSomeInfo и сохраните результат, который должен быть массивом, в свойство specialProp
  • затем для каждой записи в массиве specialProp вы хотите вызвать метод getSomeOtherInfo, извлечь еще данные и сохранить их в свойстве под названием anotherSpecialProp

Если все это правда, то вы можете попробовать что-то в этом роде

getArray()
.pipe(
    mergeMap(mainArray => mainArray),  // unwind the array received
    switchMap(mainItem => getSomeInfo(mainItem.id) // fetch the first set of info from backend
        .pipe(
            tap(someInfo => {
                mainItem['specialProp'] = someInfo; // wrote someInfo into specialProp property
            }),
            mergeMap(specialProps => specialProps), // unwind the array of specialProps
            switchMap(specialProp => getSomeOtherInfo(specialProp.name) // for each specialProp fetch the additional data
                .pipe(
                    tap(someOtherInfo => {
                        specialProp['anotherSpecialProp'] = someOtherInfo // store additional data into anotherSpecialProp property
                    })
                )
            ),
            toArray(), // rewind the array of  specialProps and return it
            map(() => mainItem)
        )
    ),
    toArray() // rewind the array of mainItems and return it
)

То, что вы можете заметить, это использование mergeMap с массивом, например mergeMap(mainArray => mainArray).

mergeMap принимает в качестве входных данных функцию, которая возвращает ObservableInput . Массив - это ObservableInput , который генерирует все свои элементы синхронно до того, как завершит . Таким образом, передача функции, возвращающей массив, в mergeMap означает испускание всех элементов массива.

Вы можете найти пример выше здесь

2 голосов
/ 26 марта 2019

Основная хитрость заключается в использовании map для объединения свойства области действия с результатом запроса.

Вот пример того, как этого достичь для первого уровня (specialProp):

this.http.get(url).pipe(
  mergeMap(mainItemArr => {
    // forkJoin will wait for each request to complete
    return forkJoin(
      // make a subsequent request for each item in mainItemArr
      mainItemArr.map(mainItem => {
        return this.getSomeInfo(mainItem.Id).pipe(
          // merge getSomeInfo result with the mainItem
          map(someInfo => {
            return {
              ...mainItem,
              specialProp: someInfo
            };
          })
        )
      })
    )
  })
)

Для запросов anotherSpecialProp - вам нужно пойти на один уровень глубже.

В реальном приложении я бы предложил разделить эти последующие вызовы на отдельные функции / методы.

ПРИМЕЧАНИЕ :

Вам не нужно превращать массив в Observable:

mergeMap(mainArray => mainArray)

Вместо этого вы можете оставить его в области действия JS и выполнить последующие запросы в mergeMap, например ::

mergeMap(mainArray => {
  // making sub requests here
})

Использование mergeMap для превращения массива в Observable также должно работать, хотя это может быть более запутанным при погружении на 1 уровень глубже, imho. Во всяком случае, map делает основной трюк.

Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...