在Angular2中循环一个observable

时间:2017-12-13 07:17:08

标签: angular asynchronous

如何简单地循环一个observable?

假设我想要执行一次可观察的五次,它会像下面的代码一样。

我的代码中发生了什么

(1)我查询并且函数返回一个名为'posts'的json

(2)对于我想要执行可观察的每个“帖子”

(3)我将步骤(2)的结果推送到我的数组

// (1)
this.communityPostProvider.query({})
  .subscribe(posts => {

    // (2)
    for(let i=0; i < posts.length; i++) {
        this.getFeaturedApi(i)
        .subscribe(result => {
            // (3)
            this.communityPosts.push(posts[i]);
            this.communityPosts[i].featured_media = result;      
      });
   });

这个问题是for循环在我的observable之前完全执行。到observable执行时,for循环已经完成。

我是angular2的新手。请帮忙!

4 个答案:

答案 0 :(得分:0)

试试这个:

this.communityPostProvider.query({})
  .map(posts => {
     for(var i=0; i<posts.length; i++){
     this.getFeaturedApi(i)
        .subscribe(result=> {
            posts[i].featured_media = result;
            this.communityPosts.push(posts[i]);
     }
     return posts;
   })
  .subscribe(posts => {
     // your posts with featured_media
   });

如果使用rxjs&gt; = 5.5,请使用.pipe(map(...))

要了解如何使用地图和其他rxjs运算符here

要了解新的rxjs可调函数,here

答案 1 :(得分:0)

如果您能够在功能中编辑代码

this.getFeaturedApi(i)

当你返回结果时,只需通过&#34; i&#34;返回结果,所以端点将知道推入数组的索引。

例如。

this.getFeaturedApi(i:number){
// your code 
return {result:result, index:i};

并在你的for循环中

// (2)
for(let i=0; i < posts.length; i++) {
    this.getFeaturedApi(i)
    .subscribe(result => {
        // (3)
        this.communityPosts.push(posts[result.index);
        this.communityPosts[result.index].featured_media = result.result;      
  });

现在你用索引收到结果了。所以你确切地知道推入数组的索引。

希望它会有所帮助。

答案 2 :(得分:0)

您应该能够将flatMaprangecombineLatest结合使用,以获得更好的结果。

此版本与您的结构非常相似。


this.communityPostProvider.query({})
  .flatMap(posts => {
    return Observable.range(0, posts.length-1)
    .map(i=> {
        return {index: i, post: posts[i]};
    })
  })
  .flatMap(postWithIndex => Observable.forkJoin([Observable.of(postWithIndex), this.getFeaturedApi(postWithIndex.index)])
  .subscribe(result => {
    // result = [{index: i, post: posts[i]}, resultFromFeature]
    this.communityPosts.push(result[0].post]);
    this.communityPosts[result[0].index].featured_media = result[1];      
  });

但我建议重构一下,因为它更清洁,更符合流媒体API。

this.communityPostProvider.query({})
  .flatMap(posts => {
    return Observable.range(0, posts.length-1)
    .map(i=> {
        return {index: i, post: posts[i]};
    })
  })
  .flatMap(postWithIndex => Observable.forkJoin([Observable.of(postWithIndex.post), this.getFeaturedApi(postWithIndex.index)]))
  .map(postAndResult => {
      // result = [post, resultFromFeature]
      postAndResult[0].featured_media = postAndResult[1]
      return postAndResult[0];
  })
  .subscribe(postWithFeaturedMedia => {
    this.communityPosts.push(postWithFeaturedMedia);
  });

(这是未经测试的,因为我没有工作rxjs设置atm。)

答案 3 :(得分:0)

这也是未经测试的

mergeMap将获取一个值并返回内部可观察数据。

因此我们采用帖子数组并使用Observable的from运算符分别发出数组的每个项目,再次使用mergeMap将每个值映射到一个observable,在这种情况下,observable从调用getFeaturedApi,传入给我们的索引作为mergeMap的参数。

我们使用map将检索到的feature分配给关联的post

this.communityPostProvider.query({})
    .mergeMap((posts) => {
        return Observable.from(posts).mergeMap((post, index) => {
            this.communityPosts.push(post);
            return this.getFeaturedApi(index).map((feature) => {
                this.communityPosts[index] = feature;
                return feature;
            });
        });
    })
    .subscribe();

根据您的需要,您可以从feature上运行的地图返回postgetFeaturedApi。返回的内容将在subscribe函数中提供。