可观察 angular 2 中的多个响应

Observable for mutiple responses in angular 2

所以,我有这项服务,它首先从另一个模块调用一个函数,该模块基本上是 returns 来自外部 api 的 urls 列表。然后该服务必须 http.get 来自该列表中的所有 url(每个 url return 一个相同格式的 json 对象)然后 return然后我可以在 angular component 中使用一个单独的可观察对象。这是我的服务代码:

    import { Injectable } from '@angular/core';
    import { Http } from '@angular/http';
    import { Client } from 'external-api';
    import { Observable } from 'rxjs/Observable';
    import 'rxjs/add/operator/map';

    let client = new Client();

    @Injectable()
    export class GbDataService {
      constructor(private _http: Http) {

      }

        getGBData(): Observable<any> {
        client.fetchUrls("").then(resp=> {
        resp.forEach(url => {
          //this._http.get(url).map(res => res.json);
          // Create a single observable for every http response

        });
        }).catch(function(err){
            console.log(err.message);
        });
        //return observable
      };
   }

http.get returns 和 Observable<Response> 类型,但我找不到一种方法来为所有 http.get 响应创建和 return 一个 Observable。如何才能做到这一点 ?我是否应该创建一个可观察数组,然后 push() 我得到的所有 get 响应?

编辑:如果响应是一个接一个或一次全部发出,对我来说并不重要,但必须只有一个 Obeservable 发出所有响应http.get 个请求。

进一步编辑:这是我的 fetchURLs 方法:

  fetchURLs(): Promise<any> {
    return new Promise((resolve, reject) => {
      let _repos: Array<any>;
      //scrapeTrendingRepos() is from https://github.com/rhysd/node-github-trend
      scraper.scrapeTrendingRepos("").then(repos => {
        repos.forEach(repo => {
          let url = `https:api.github.com/repos/${repo.owner}/${repo.name}`;
          _repos.push(url);
        });
        resolve(_repos);
      }).catch(err => {
        reject(err);
      });
    })
  };

我在 fetchURLs() 中实现 Promises 了吗??

if client.fetchUrls("") return native Promise 你可能想使用 snorkpete 解决方案。

如果不尝试创建一个可观察对象:

getGBData(): Observable<any> {

   return Observable.create(observer => {
        client.fetchUrls("").then(resp=> {
        resp.forEach(url => {
          this._http.get(url).map(res => res.json).subscribe(data=>{
            observer.next(data);
          });


        });
        }).catch(function(err){
            console.log(err.message);
            observer.error(err);
        });
  });
}

所以,您发出请求并返回一组 URL,然后您想要获取所有 URL 并从中获得一个响应?

这些是 RxJS 擅长的类型。

@Injectable()
    export class GbDataService {
      constructor(private _http: Http) {

      }

      getGBData(): Observable<any> {

        return Observable
          .fromPromise(client.fetchUrls())   // returns Observable<array>
          .switchMap( urls => {  
            // convert your list of urls to a list of http requests
            let urlRequests = urls.map( url => http.get(url) );

            // combineLatest accepts an array of observables,
            // and emits an array of the last results of each of the observables
            // but the first emit only happens after every single observable
            // has emitted its first result

            // TLDR: combineLatest takes an array of Observables
            //       and will emit an array of those observable emissions       //       after all have emitted at least once
            return Observable.combineLatest(urlRequests);

          })
        }).catch(function(err){
            console.log(err.message);
        });
        //return observable
      };
   }

更多信息:

阅读 combineLatest 可观察值。在这种情况下,它完成了您希望在发出单个数组之前等待其所有可观察参数发出的结果。但是,如果您的可观察参数也发出多次,它可能不会达到您的预期,您可能想尝试不同的运算符,如 forkJoin 或 zip。

另外

您可能希望使用 switchMap 而不是 flatMap - 如果要获取的 url 的新请求通过,switchMap 将在发送新的请求列表之前取消当前正在运行的所有请求。

进一步编辑

尽管您的 fetchURLs 实现可以在其当前版本中运行,但如果您愿意,可以利用 promises 的工作方式稍微简化您的方法。在 'Promise-land' 中,then 处理程序也 return 是一个 Promise,第二个 Promise 将使用您 return 来自 [=] 的任何值进行解析12=] 处理程序 (这是基本的承诺链概念)。使用这些知识,您可以将方法简化为:

fetchURLs(): Promise<any> {
  //scrapeTrendingRepos() is from https://github.com/rhysd/node-github-trend
  return scraper.scrapeTrendingRepos("").then(repos => {
     // since repos is an array, and you wish to transform each value
     // in that array to a new value, you can use Array.map
     return repos.map( repo => `https:api.github.com/repos/${repo.owner}/${repo.name}`);
  });
}