通过ng2中的Observables进行的依赖和并行请求 [英] Dependent and parallel requests through Observables in ng2

查看:52
本文介绍了通过ng2中的Observables进行的依赖和并行请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在整理一个应用程序,该应用程序显示有关"Modyules"的信息(在课程中),该信息必须通过两个http.gets来获取(不幸的是,我无法控制api):

I am putting together an application that displays information about 'Modyules' (on a course) that it has to pull via two http.gets (I have no control over the apis unfortunately):

  1. 获取Modyule.ids列表-需要存储ID
  2. 对于每个Modyule.id,还要另外一个http.get以获取Modyule.name

在我的modyule.component.ts中,我有:

In my modyule.component.ts, I have:

this.modyuleService.getModyules()
     .subscribe(
          modyules => this.modyules = modyules,
          error =>  this.errorMessage = <any>error
     );

在我的modyule.service.ts中,我有:

In my modyule.service.ts, I have:

getModyules (): Observable<Modyule[]> {
        return this.http.get(listOfModyuleIdsUrl + '.json')
            .map(this.getModyulesDetails)
            .catch(this.handleError);
    }

但是getModyuleDetails是我苦苦挣扎的地方.到目前为止,这主要是基于以下内容:

But the getModyuleDetails is where I am struggling. This is where I have got to so far, mainly based on:

> http://www.syntaxsuccess.com/viewarticle/angular-2.0 -and-http

然后查看,但看不到如何申请:

and looking at, but not seeing how I can apply:

https://stackoverflow.com/a/35676917/2235210

private getModyulesDetails = (res: Response) => {  // instance method for defining function so that the this.http below refers to the class.
    let listOfModyules = res.json();
    let modyulesToReturn = [];

    for (let individualModyule of listOfModyules){
        let tempModyule = new Modyule;
        tempModyule.id = individualModyule.id;

        this.http.get(individualModyuleUrl + individualModyule.id + '.json')
            .map((res: Response) => res.json()))
            .subscribe(res => {
                tempModyule.name = res.name
                modyulesToReturn.push(tempModyule);
            });
        }
    return modyulesToReturn;      
}

现在这在我的本地计算机上工作了,在该计算机上我已将.json响应模拟为静态.json文件..但是,当我处理真正的api时,我不能依赖于http.gets在返回modyulesToReturn之前,for循环已经完成.

Now this is working on my local machine where I have mocked up the .json responses as static .json files..but, when I'm dealing with the real api, I can't rely on the http.gets in the for loop to have completed before returning modyulesToReturn.

我在forkJoin上进行了几次尝试,但是看不到如何将其与从第一个http.get捕获Modyule.id的需求结合起来.

I've had a couple of attempts at forkJoin but don't see how I can combine this with the requirement to capture the Modyule.id from the first http.get.

对于任何如何根据初始请求进行并行请求并能够合并来自两者的数据的指针,我将不胜感激.

I'd be very grateful for any pointers for how to do parallel requests which depend on an initial request and yet be able to combine data from both.

根据与@Matt和@batesiiic的讨论进行

EDIT in reponse to discussion with @Matt and @batesiiic:

因此,在@batesiiic建议的getModyulesDetails重写以返回Subject的建议上,我无法理解的问题是如何在第一个调用中填充Modyule.id,然后在第二个调用中填充Modyule.name调用(不返回对Modyule.id的任何引用),即:

So, picking up on @batesiiic's suggested rewrite of getModyulesDetails to return a Subject, the problem I can't get my head around is how to populate the Modyule.id in the first call and then the Modyule.name in the second call (which doesn't return any reference to the Modyule.id) ie:

private getModyulesDetails = (res: Response) => {  // instance method for defining function so that the this.http below refers to the class.
    let listOfModyules = res.json();
    let modyulesToReturn = [];
    let calls = [];

    for (let individualModyule of listOfModyules){
        /* I REALLY NEED TO POPULATE Modyule.id HERE */
        calls.push(
            this.http.get(individualModyuleUrl + individualModyule.id + '.json')
                .map((res: Response) => res.json()))
        );
    }

    var subject = new Subject<Modyules[]>();

    Observable.zip.apply(null, calls).subscribe((modyules: Modyules[]) => {
        var modyulesToReturn = [];
        modyules.forEach(modyule => {
            let tempModyule = new Modyule;
            /*I COULD POPULATE Modyle.name HERE BUT IT WON'T MATCH THE Modyule.id SET ABOVE - EXCEPT BY LUCK*/
            modyulesToReturn.push(tempModyule);
        }
        subject.next(modyulesToReturn);
    });

    return subject;      
}

我认为我需要在for循环中一个接一个地进行调用,但是以某种方式等到它们全部响应后才返回modyulesToReturn?

I think I need to make the calls one by one in the for loop but somehow wait until they have all responded before returning the modyulesToReturn?

推荐答案

好吧,多亏了@ batesiiic,@ Matt(我对你的回答都表示支持)和一个有用的小时(与两者相比,沧海一粟漫长的夜晚和整个星期六,我已经在此度过了!)花了 Angular University ,我有一个可行的解决方案(无论如何,到目前为止!). .switchMap将两个请求链接在一起,将Observable从第一个传递到第二个,@ batesiiic出色的Subject思想(和forkJoin-我无法压缩工作)以及实现我的Modyule.id依赖的实现通过查看响应对象本身来请求请求!

Well, thanks to both @batesiiic, @Matt (I've upvoted both your answers) and a useful hour (a drop in the ocean compared to the two long evenings and the whole of a Saturday I've spent on this already!) spent watching Angular University, I have a working solution (so far anyway!). .switchMap to chain two requests together, passing the Observable from the first into the second, @batesiiic's brilliant Subject idea (and forkJoin - I couldn't get zip to work) and the realisation that I could get my Modyule.id in the dependent request by looking at the response object itself!

在ngOnInit()的modyule.component.ts中:

In modyule.component.ts in ngOnInit():

this.modyuleService.getModyules()
        .switchMap(modyules =>this.modyuleService.getModyulesDetails(modyules)) 
        .subscribe(
            modyules => {
                this.modyules = modyules  
                },
           error =>  this.errorMessage = <any>error);

以及在module.service.ts中:

and in module.service.ts:

getModyules (): Observable<Modyule[]> {
    return this.http.get(this.listOfModyuleIdsUrl)
        .map(this.initialiseModyules)
        .catch(this.handleError);            
}

private initialiseModyules(res: Response){
    let body = res.json();
    let modyulesToReturn = [];
    for (let individualModyule of listOfModyules){
        let tempModyule = new Modyule;
        tempModyule.id = individualModyule.id;
        modyulesToReturn.push(tempModyule);
        }
    }
    return modyulesToReturn;
}

getModyulesDetails (modyules:Modyule[]): Observable<Modyule[]> {
    let calls  = [];

    for (let modyule of modyules){
        calls.push(
            this.http.get(this.individualModyuleUrl + modyule.id + '.json')
            );
    }

    var subject = new Subject<Modyule[]>();   

    Observable.forkJoin(calls).subscribe((res: any) => {
        for (let response of res){
            //Note this is a really very awkward way of matching modyule with a id assigned in getModyules (above) with the correct response from forkJoin (could come back in any order), by looking at the requested url from the response object
            let foundModyule = modyules.find(modyule=> {
                let modyuleUrl = this.individualModyuleUrl + modyule.id + '.json';
                return modyuleUrl === response.url;
            });
            let bodyAsJson = JSON.parse(response._body);
            foundModyule.name = res.name;
            }
        subject.next(modyules);
    });

    return subject;
}

希望对别人有帮助.但是,仍然不禁感到应该有某种方法不从多个调用中返回以获取详细信息,直到它们全部完成为止,而不必对所有不再有的.forkJoin或.zip求助于免费.与调用模块的关系,除非通过查看response.url ...

Hope that helps someone else. However, still can't help feeling that there ought to be some way to not return from multiple calls to get details until they have all finished, without having to resort to the free for all of .forkJoin or .zip where you no longer have a relationship with the calling modyule except by looking at the response.url...

再次感谢您的所有帮助.

Thanks again for all your help.

这篇关于通过ng2中的Observables进行的依赖和并行请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆