让多个组件构建一个HTTP请求

时间:2017-03-14 14:37:31

标签: angular typescript

目前我的应用程序有一个数据服务,它向服务器发出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));
}

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

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

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方法的body参数,并只生成一个http请求?

编辑:我也希望对此进行扩展,以便最终我可以说10个以上的组件,每个组件都有自己的本地数据集来请求。

2 个答案:

答案 0 :(得分: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;
}

我已缓存observable以便返回if后续请求。因此,如果我们有一个正在进行的请求(让我们说医院),并要求诊所的API,直到医院还没有退回,我们将不会提出额外的请求。将返回现有的observable并且两个组件(Hospitals and Clinics)都可以单独处理响应。

此外,我还添加了一些cleanUp代码,以便在请求完成后删除缓存的Observable。后续请求将再次命中API。

注意:我尚未测试此代码,因此可能需要进行一些其他更改。

答案 1 :(得分:1)

调用服务获取数据后,您可以等到所有ngZone微任务完成(其中包括可能对服务做出的任何其他请求),然后触发单个{{1}请求。您需要修改http方法以返回getLocalData rxjs,一旦数据从服务器返回,您就可以在主题上发布数据,以便将它们传递回适当的呼叫者。

免责声明 我不完全确定这是否是解决此问题的最佳方式,但上述情况应该有效。

以下是修改后的服务和Subject方法。

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]; 地图进行创建以启用请求多个集合而不是单个集合。

Demo