在角度2中可观察到多个响应

时间:2017-03-30 13:35:29

标签: javascript angular http rxjs

所以,我有这个服务首先从另一个模块调用一个函数,它基本上从外部api返回一个url列表。然后,该服务必须http.get来自该列表中的所有URL(每个url返回相同格式的json对象),然后返回单个observable,然后我可以在角度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返回Observable<Response>类型,但我找不到为所有http.get响应创建和返回一个Observable的方法。如何才能做到这一点 ?我应该创建一个可观察的数组,然后push()我得到数组的所有get响应吗?

编辑:如果响应一个接一个地发出或者一次发出,那对我来说并不重要但是必须只有一个Obeservable发出所有{{1}的响应请求。

进一步修改:这是我的fetchURLs方法:

http.get

我是否已在 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); }); }) }; 中实施了Promise

2 个答案:

答案 0 :(得分:3)

那么,您发出请求并获取一系列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 observable。在这种情况下,它会在发出单个数组之前完成您想要等待所有可观察参数发出的内容。但是如果你的可观察参数也会多次发出,它可能无法达到预期效果,你可能想尝试使用forkJoin或zip等不同的运算符。

<强>另外

您可能希望使用switchMap而不是flatMap - 如果有新的URL提取请求,switchMap将在发送新的请求列表之前取消当前正在进行的任何请求。

进一步修改

虽然你的fetchURLs实现可以在其当前版本中使用,但如果你希望利用promises如何工作,你可以稍微简化你的方法。在“Promise-land”中,then处理程序还返回Promise,第二个Promise将以您从then处理程序返回的任何值解析(这是链接概念的基本承诺)。使用这些知识,您可以简化您的方法:

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}`);
  });
}

答案 1 :(得分:1)

如果client.fetchUrls("")返回原生 Promise,您可能需要使用snorkpete解决方案。

如果没有尝试创建一个observable:

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);
        });
  });
}