RxJS Observable返回数组,每次迭代运行另一个函数

时间:2016-06-23 20:14:54

标签: javascript angularjs rxjs observable

我有一个函数getNews(),它基本上返回了angular的http.get请求。请求的结果是Id的数组。我想迭代我得到的这个数组并运行另一个http.get请求(函数getItem(id)),然后返回从服务器收到的单个Id的对象。

我尝试过这样使用它:

  getLatest() {
    return this.http.get('all_news_url')
    .map(res => res.json())
    // I even tried creating Observable from array and get only 5 elements
    //.map(res => Observable.from(res.json()))
    //.take(5)
    .map((data) => this.getItem(data))
    .subscribe(
      data => {
        console.log(data);
      }
    )
  }

  getItem(itemId: any): Observable<any> {
    console.log('item id', itemId);

    return this.http.get(this.generateUrl(`item/${itemId}`))
    .map(res => res.json());
  }

显然,这不起作用。 getItem()函数的参数总是作为Id的整个数组传递。

感谢大家参与这个问题。

2 个答案:

答案 0 :(得分:9)

您可能希望使用concatMap运算符而不是map。 concatMap将返回的Observable展平为源Observable,而map返回一个可观察的observable。

如果您希望getItem()中的数据与'all_news_url'中列出的顺序相同,您可以尝试类似

的内容
this.http.get('all_news_url')
.concatMap(res => Observable.from(res.json()).take(5))
.concatMap((data) => this.getItem(data))
.subscribe(
  data => {
    console.log(data);
  }
);

使用上面的代码,对getItem()的调用将是同步的,即一次只有一个请求'item / $ {itemId}',并按顺序

如果您不关心订单并想通过一次发送多个请求来加速订单,请将第二个concatMap更改为mergeMap。请注意,请求(对于item / itemId)仍然是有序的,但不能保证响应的顺序。您可以将最大并发请求作为第三参数提供给mergeMap(通过传递undefined或null忽略第二个参数)。

.concatMap(res => Observable.from(res.json()).take(5))
.mergeMap((data) => this.getItem(data), null, 3)

传递1作为mergeMap的第三个参数将等同于concatMap

答案 1 :(得分:1)

问题

  • /list --> 项目[]
  • /item?item_id={id} --> 带有额外内容的项目
  • 让我们用额外的东西来获取 Item[]

解决方案 concatMap to zip itemRequests

getList(): Observable<Item> {
  return this.http.get('/list').pipe(
    concatMap(list => {
      const itemRequests = list.map(item => this.getItem(item))
      return zip(...itemRequests)
    })
  )
}

getItem(item: Item): Observable<Item> {
  return this.http.get(`/item?item_id=${item.id}`)
}

完成!

getList().subscribe((items: Item[]) => {
  console.log(items)
})