Angular 等待可观测在可观测范围内完成

Angular 等待可观测在可观测范围内完成,angular,typescript,observable,Angular,Typescript,Observable,我有以下数据结构: export class Repo { id: number; name: string; contributors: Contributor[]; } export class Contributor { id: number; login: string; } 我正在使用Observable获取所有回购数据,但我想在外部repo被认为完全发出之前,在内部调用另一个ObservableObservable来填充所有参与者。我不知道

我有以下数据结构:

export class Repo {
    id: number;
    name: string;
    contributors: Contributor[];
}

export class Contributor {
    id: number;
    login: string;
}
我正在使用
Observable
获取所有回购数据,但我想在外部
repo
被认为完全发出之前,在内部调用另一个Observable
Observable
来填充所有参与者。我不知道该怎么做。我有以下代码

private repos: Repo[] = [];

getRepos(orgName: string): void {
    const repoBuild: Repo[] = [];
    this.githubService.getRepos(orgName).pipe(
        // this here won't wait for all contributors to be resolved
        map(repo => this.getRepoContributors(orgName, repo))
    ).subscribe(
        repo => repoBuild.push(repo),
        error => {
            this.repos = [];
            console.log(error);
        },
        () => this.repos = repoBuild
    );
}

// fetches contributors data for the repo
private getRepoContributors(orgName: string, repo: Repo): Repo {
    const contributors: Contributor[] = [];
    repo.contributors = contributors;
    this.githubService.getRepoContributors(orgName, repo.name)
        .subscribe(
            contributor => {
                // add to the total collection of contributors for this repo
                contributors.push(contributor);
            },
            error => console.log(error),
            () => repo.contributors = contributors
        );
    return repo;
}
我承认我对可观测的的理解是有限的,我为此奋斗了好几个小时。我试图在StackOverflow上找到适合我的东西,但仍然找不到有效的解决方案。任何帮助都将不胜感激

(代码是用角5写的)

解决方案:

我在下面使用了@joh04667建议,并最终使其生效。我是这样做的:

getRepos(orgName: string): void {
    const repoBuild: Repo[] = [];
    this.githubService.getRepos(orgName).pipe(
        // mergeMap() replaces `repo` with the result of the observable from `getRepoContributors`
        mergeMap(repo => this.getRepoContributors(orgName, repo))
    ).subscribe(
        repo => repoBuild.push(repo),
        error => {
            this.repos = [];
            console.log(error);
        },
        () => this.repos = repoBuild
    );
}

// fetches contributors data for the repo
private getRepoContributors(orgName: string, repo: Repo): Observable<Repo> {
    repo.contributors = []; // make sure each repo has an empty array of contributors
    return this.githubService.getRepoContributors(orgName, repo.name).pipe(
        // tap() allows us to peek on each contributor and add them to the array of contributors
        tap(contributor => {
            // add to the total collection of contributors for this repo
            repo.contributors.push(contributor);
        }),
        // only picks the last contributor and replaces him/her with the repo
        last(
            () => false,
            () => repo,
            repo
        )
    );
}
getRepos(组织名称:字符串):无效{
常量repoBuild:Repo[]=[];
这个.githubService.getRepos(orgName).pipe(
//mergeMap()将“repo”替换为“getrepo”的可观察结果`
mergeMap(repo=>this.getRepoContributors(orgName,repo))
).订阅(
repo=>repoBuild.push(repo),
错误=>{
本公司回购利率=[];
console.log(错误);
},
()=>this.repos=repoBuild
);
}
//获取回购协议的参与者数据
私有getRepoContributors(orgName:string,repo:repo):可观察{
repo.contributors=[];//确保每个repo都有一个空的参与者数组
返回这个.githubService.getRepoContributors(orgName,repo.name).pipe(
//tap()允许我们查看每个贡献者并将其添加到贡献者数组中
点击(参与者=>{
//添加到此回购协议的供款人总集合中
回购贡献者推送(贡献者);
}),
//仅选择最后一位供款人,并用回购协议替换他/她
最后(
()=>错,
()=>回购,
回购
)
);
}

在最后一部分中,我使用了
last()
我基本上告诉了
可观察的
,即使它会处理所有的值,我也只会使用最后一个值。最后一个类型是
Contributor
,但我用一个默认值(即
repo
)替换它,它允许我将返回类型从
Observable
更改为
Observable
,这正是我需要更高级别的Observable,对我来说,这是真正理解可观察物的全部力量的“大步”:高阶可观察物,或返回可观察物的可观察物

您的情况非常适合操作员:

getRepos(orgName: string): void {
    const repoBuild: Repo[] = [];
    this.githubService.getRepos(orgName).pipe(
        // this will map the emissions of getRepos to getRepoContributors and return a single flattened Observable
        mergeMap(repo => this.getRepoContributors(orgName, repo))
    ).subscribe(
        repo => repoBuild.push(repo),
        error => {
            this.repos = [];
            console.log(error);
        },
        () => this.repos = repoBuild
    );
}
mergeMap
将外部可观察对象的发射映射到内部可观察对象(
getRepos
),并返回仅在内部可观察对象完成时发射的新可观察对象。换言之,它将从一个可观测值传递到另一个可观测值的值展平到一个简洁的可订阅数据流中

高阶观测值很难让你头脑清醒,但这才是观测值真正的力量所在。我强烈建议在我链接的站点上查看其他一些操作符,如
switchMap
concatMap
。当使用到最大程度时,可观察物会变得异常强大

编辑 我误读了原始代码,认为
getRepoContributors
返回了一个可观察的。漫长的工作日把我累坏了。我将在这里重构:

map
用于在与
mergeMap
合并之前更改值。可以在那里完成
getRepoContributors
的前几行。由于
mergeMap
需要返回一个可观察的对象,我们可以稍微简化一下:

private repos: Repo[] = [];

getRepos(orgName: string): void {
    const repoBuild: Repo[] = [];
    this.githubService.getRepos(orgName).pipe(
        map(repo => {
            repo.contributors = [];
            return repo;
          }),
        mergeMap(repo => this.githubService.getRepoContributors(orgName, repo.name)),
        map(contributor => {
            repo.contributors.push(contributor)
          })
    ).subscribe(
        repo => repoBuild.push(repo),
        error => {
            this.repos = [];
            console.log(error);
        },
        () => this.repos = repoBuild
    );
}

// don't need second function anymore

我们可以在流中
映射
,期望值按顺序与运算符一起更改。

您是否尝试过使用switchmap或flatmap运算符Hey@joh04667谢谢您的回答,但我无法让它工作。这就是我的问题:我需要发出一个
repo
,这样我就可以将它传递给
getrepoaccomponents
,在那里它使用
repo.name
来获取贡献者,然后我订阅
getrepoamporters
,以收集数组中的所有参与者,订阅完成后,我将这些参与者分配回
repo
。使用
mergeMap
的这种方法会将我的
Observable
转换为
Observable
,因此当我订阅时,我不再有权获得回购。啊,明白了。没有看到您在第二个方法中订阅了另一个可观察对象,而不是返回一个可观察对象。我会更新我的答案。