2017-03-14 16 views
2

目前我的应用程序有一个数据服务,它向服务器发送一个http请求以获取数据。每个组件都会对该服务进行单独调用以获取所需的数据。有多个组件构建一个HTTP请求

public getHospitals() { 
    return this._http.get(this.baseUrl + "/hospitals/") 
     .map(res => res.json()) 
     .map(json => automapper.map(typeof (JSON), Hospital, json)); 
} 

public getClinics() { 
    return this._http.get(this.baseUrl + "/clinics/") 
     .map(res => res.json()) 
     .map(json => automapper.map(typeof (JSON), Clinic, json)); 
} 

当我加载我的示例页面时,我有一个医院组件和一个诊所组件。这两个组件调用数据服务中的相应方法。

我最近扩展了服务器以允许一个请求指定它需要的数据。下面是一个如何调用它的例子。

public getLocalData(body) { 
    const headers = new Headers({ "Content-Type": "application/json" }); 
    const options = new RequestOptions({ headers }); 
    return this._http.post(this.baseUrl, JSON.stringify(body), options) 
     .map(res => res.json()); 
} 

public getHospitals() { 
    return this.getLocalData(["Hospitals"]) 
     .map(json => automapper.map(typeof (JSON), Hospital, json.Hospitals)); 
} 

public getClinics() { 
    return this.getLocalData(["Clinics"]) 
     .map(json => automapper.map(typeof (JSON), Clinic, json.Clinics)); 
} 

这可能不是这样调用,这将返回回的所有数据:const localData = this.getLocalData(["Hospitals", "Clinics"]);

我的问题是,我该如何修改这两个组件来打造为getLocalData方法的身体参数,只做一个http请求?

编辑:我也想扩展这个,以便最终我可以说10 +组件,每个组件都有自己的一组本地数据请求。

回答

1

一旦您的服务被调用以获取数据,您可以等到所有ngZone微任务完成(其中包括可能对服务进行的任何其他请求),然后发出单个http请求。您需要修改getLocalData方法以返回rxjsSubject,并且一旦数据从服务器返回,您可以在主题上发送数据,以便将它们传回给适当的调用者。

免责声明我不能完全肯定,如果这是解决这个问题的最好办法,但上面的应该工作。

这里是修改的服务和getLocalData方法。

import {Observable} from "rxjs/Observable"; 
import "rxjs/add/operator/map"; 
import "rxjs/add/operator/first"; 
import {Subject} from "rxjs/Subject"; 

// ... 

public getHospitals() { 
    return this.getLocalData("Hospitals") 
     .map(json => automapper.map(typeof (JSON), Hospital, json.Hospitals)); 
} 

public getClinics() { 
    return this.getLocalData("Clinics") 
     .map(json => automapper.map(typeof (JSON), Clinic, json.Clinics)); 
} 

private requests = {}; 
private isAggregating = false; 
private getLocalData(dataKey): Subject { 
    this.requests[dataKey] = this.requests[dataKey] || new Subject(); 

    if(!this.isAggregating){ 
     this.isAggregating = true; 
     this.ngZone.onMicrotaskEmpty.first().subscribe(() => { 
      var requests = this.requests; 
      this.requests = {}; 
      this.isAggregating = false; 

      const headers = new Headers({ "Content-Type": "application/json" }); 
      const options = new RequestOptions({ headers }); 

      this._http.post(this.baseUrl, JSON.stringify(Object.keys(requests)), options) 
       .map(res => { 
        return res.json(); 
       }).subscribe((data) => { 
        Object.keys(data) 
         .filter((key) => requests[key]) 
         .forEach((key)=>{ 
          requests[key].next(data[key]); 
          requests[key].complete(); 
         }); 
       }); 
     }); 
    } 

    return this.requests[dataKey]; 

}

我不知道如何在你的问题中指示,但我相信有一种方式来获得与创造改写,使得个性化的服务方法可以要求多组数据映射到requests以启用请求多个集而不是单个集。

Demo

1

也许你想实现这样的事情:

@Injectable() 
export class LocalDataService { 
    private getLocalData(body) { 
     const headers = new Headers({ "Content-Type": "application/json" }); 
     const options = new RequestOptions({ headers }); 
     return this._http.post(this.baseUrl, JSON.stringify(body), options) 
      .map(res => res.json()); 
    } 

    public getHospitals() { 
     if (!this.pendingRequest) { 
      this.pendingRequest = this.getLocalData(["Hospitals", "Clinics"]); 
      this.cleanUpSubscription = this.pendingRequest.subscribe(() => this.cleanUp(),() => this.cleanUp()); 
     } 

     return this.pendingRequest.map(json => automapper.map(typeof (JSON), Hospital, json.Hospitals)); 
    } 

    public getClinics() { 
     if (!this.pendingRequest) { 
      this.pendingRequest = this.getLocalData(["Hospitals", "Clinics"]); 
      this.cleanUpSubscription = this.pendingRequest.subscribe(() => this.cleanUp(),() => this.cleanUp()); 
     } 

     return this.pendingRequest.map(json => automapper.map(typeof (JSON), Clinic, json.Clinics)); 
    } 

    private cleanUp() { 
     if (this.cleanUpSubscription) { 
      this.cleanUpSubscription.unsubscribe(); 
      this.cleanUpSubscription = null; 
     } 

     this.pendingRequest = null; 
    } 

    private pendingRequest: Observable<Response> = null; 
    private cleanUpSubscription: Subscription = null; 
} 

我为了回报如果后续请求缓存观察到。因此,如果我们有一个请求正在进行(比如说医院),并且要求API for Clinics,直到医院尚未返回,我们将不会提出额外请求。现有的可观察项目将被退回,并且两个组件(医院和诊所)都可以单独处理。

此外,我已经添加了一些清理代码,以便在请求完成后删除缓存的Observable。随后的请求将再次击中API。

注意:我没有测试过这段代码,因此可能需要进行一些更改。

+0

这是如何扩展和扩展的?一旦我找到20种不同类型的数据呼叫,我该怎么办?并非所有这些调用都需要为每个页面进行,所以我不想要求所有这些调用。 – Stout01

+0

没有什么说你在问题中有两个以上的组件。因此请根据您的实际要求更新您的问题。如果你想为几个独立的组件提出一个请求,我认为你应该有一个知道它的子组件(诊所,医院等)的父组件。当所有子组件加载(ngAfterViewInit)时,父组件可以执行网络请求,并通过Input参数将Observable传递给子组件。 –