【问题标题】:RxJS Observable returning array, run another function with each array iterationRxJS Observable 返回数组,每次数组迭代运行另一个函数
【发布时间】:2016-06-23 20:14:53
【问题描述】:

我有一个函数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 数组传递。

感谢大家参与这个问题。

【问题讨论】:

    标签: javascript angularjs rxjs observable


    【解决方案1】:

    您可能希望使用 concatMap 运算符而不是 map。 concatMap 将返回的 Observable 扁平化为源 Observable,而 map 返回一个 observable 的 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)仍然是有序的,但不能保证响应的顺序。您可以将最大并发请求作为 third 参数提供给 mergeMap(通过传递 undefined 或 null 来忽略第二个参数)。

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

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

    【讨论】:

    • 这正是我想要的。只有一个小错字,在您发布的代码的第一部分,不需要.map(res =&gt; res.json())。非常感谢。
    • 你是对的@gregor。我没有太注意就复制粘贴了;)
    【解决方案2】:

    问题

    • /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)
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-26
      • 2017-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-10
      • 2021-12-02
      • 1970-01-01
      相关资源
      最近更新 更多