循环数组时Angular RxJs升高

时间:2019-03-25 14:53:36

标签: angular http rxjs

我有一个http get请求,以获取类似的数组

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

我需要获取每个数组项,获取一个ID,然后向服务器发送请求以获取一些信息。结果应写入属性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 个答案:

答案 0 :(得分:3)

如果我做对了,您需要执行的操作如下:

  • 从后端获取初始数组
  • 对于数组的每个元素,调用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的函数意味着发出该数组的所有元素。

您可以找到above example here

的示例

答案 1 :(得分:2)

主要技巧是使用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请求-您需要更深入一层。

在现实世界的应用程序中,我建议将这些后续调用分成单独的函数/方法。

注意

您不需要将数组变成可观察的:

mergeMap(mainArray => mainArray)

相反,您可以将其保留在JS范围内,然后在mergeMap中进行后续请求,例如:

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

使用mergeMap将数组转换为Observable也是可行的,尽管在深入1级时可能会更加混乱,恕我直言。无论如何,map是主要技巧。

希望这会有所帮助