[英]Wait for Observable to complete within an Observable
我有以下數據結構:
export class Repo {
id: number;
name: string;
contributors: Contributor[];
}
export class Contributor {
id: number;
login: string;
}
我正在使用Observable<Repo>
來獲取所有回購數據,但是我想內部調用另一個observable Observable<Contributor>
來填充所有貢獻者,然后再將外部Repo
視為完全發出。 我不確定該怎么做。 我有以下代碼。
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;
}
我承認我對Observable
的理解是有限的,並且我為此苦苦掙扎了好幾個小時。 我試圖在StackOverflow上找到對我有用的東西,但仍然找不到有效的解決方案。 任何幫助,將不勝感激!
(代碼是用Angular 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
)
);
}
在我使用last()
的最后一部分中,我基本上告訴Observable
,即使它將處理所有值,我也只會消耗最后一個。 最后一個是Contributor
類型,但我將其替換為默認值( repo
),這使我可以將返回類型從Observable<Contributor>
更改為Observable<Repo>
,這正是我對更高級別的Observable所需要的。
這是一個很好的問題,對我來說,這是真正理解Observable的全部功能的“重大步驟”:高階Observable或返回Observable的Observable。
您的情況對於mergeMap / flatMap
運算符是完美的:
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
將外部Observable (getRepos)
發射映射到內部Observable( getRepoContributors
),並返回僅在內部Observable完成時才發射的新Observable。 換句話說,它將從一個Observable傳遞到另一個Observable數據流的值展平。
高階可觀察物可能很難纏住你的頭,但這確實是可觀察物真正力量所在。 我強烈建議在我鏈接的站點上也檢查其他一些運算符,例如switchMap
和concatMap
。 充分利用可觀察者的力量,他們會變得瘋狂起來。
我誤讀了原始代碼,以為getRepoContributors
返回了一個Observable。 漫長的一天讓我炸了。 我將在這里重構:
map
在將值與mergeMap
合並之前可以更改其值。 可以在此處完成getRepoContributors
的前幾行。 由於mergeMap
需要返回一個Observable,因此我們可以簡化一下:
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
我們可以在流中map
,以期望值與操作員按順序進行更改。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.