我有一组Observable,它们分别检索不同的数据类型。我将那些Observable链接起来,以获得我想要的页面所有数据。 事实是所有这些信息都是独立的,因此加载一个信息不应阻止或干扰加载其他信息。我无法实现。
以下是我目前所做的一个示例:
getAll(): Observable<any[]> {
return this.getHome().pipe(
tap((home: Home) => this.application = home),
mergeMap((home: Home) =>
combineLatest([
this.getAssets(home.images).pipe(defaultIfEmpty([])),
this.getStyling(home.styling).pipe(defaultIfEmpty({})),
this.getCategories(home.categories).pipe(defaultIfEmpty([])),
])
)
);
}
在这里,Observable已成功链接,所以我得到了我想要的所有数据,但是combineLatest()
在前一个请求完成后会执行下一个请求,而在一切完成后,parent将发出收集的数据,这会产生延迟。
我一直在尝试使用merge()
而不是combineLatest()
,以便接收到的每个数据都立即将其发送给父级Observable,但显然我做不到
那么,我如何管理这些Observable的链接,以便子Observable中的每个提交都直接向父Observable发出?
答案 0 :(得分:5)
您需要forkJoin
,它会返回一个Array
和每个Observable
的结果(与forkJoin
参数的顺序相同。
getAll(): Observable<any[]> {
return this.getHome().pipe(
tap((home: Home) => this.application = home),
mergeMap((home: Home) =>
forkJoin(
this.getAssets(home.images).pipe(defaultIfEmpty([])),
this.getStyling(home.styling).pipe(defaultIfEmpty({})),
this.getCategories(home.categories).pipe(defaultIfEmpty([]))
)
)
);
}
答案 1 :(得分:3)
如果它们是独立的,则可以独立处理它们并将它们发射到主题上。
getAll(): Observable<any> {
const subject = new Subject<any>();
const handler = (res: any) => subject.next(res);
this.getHome().pipe(
tap((home: Home) => this.application = home),
tap(handler),
tap((home: Home) => {
forkJoin(
this.getAssets(home.images).pipe(defaultIfEmpty([]),tap(handler))
this.getStyling(home.styling).pipe(defaultIfEmpty({}), tap(handler))
this.getCategories(home.categories).pipe(defaultIfEmpty([]), tap(handler))
).subscribe(res => subject.complete())
})
).subscribe();
return subject.asObservable();
}
使用这种方法,类型检查必须由使用者完成。
答案 2 :(得分:1)
我一直在尝试使用merge()而不是CombineLatest(),这样接收到的每个数据都会立即将其发送给父Observable,但是显然我做不到
听起来好像您在准备 partial 数据时就在寻找它。 combineLatest()和forkJoin()都只会在可以填充与可观察对象数量相等长度的数组时才发射数据。因此,您要么等待每个可观察值中的至少一个值,要么等待它们全部完成,但是它们发出一个数组,并且他们需要知道要在其中放置什么。
我认为您想在准备好每条数据后立即将其发送出去。
首先使用merge()从所有3个可观察对象中发出值,但是对于每个可观察对象,请使用map()为该给定类型(图像,样式,类别)创建对象键/值对。 / p>
最后,使用scan()运算符将值聚合到一个对象中,该对象将在更新每个属性时发出。
流的消费者可以检查属性是否为null
,以查看其是否准备就绪。该流将在完成之前发出3个值。
getAll(): Observable<{home: Home, images: any[], styling: any[], categories: any[]}> {
return this.getHome().pipe(
tap((home: Home) => this.application = home),
switchMap((home: Home) =>
merge([
this.getAssets(home.images).pipe(
defaultIfEmpty([]),
map(images => ({images}))
),
this.getStyling(home.styling).pipe(
defaultIfEmpty({}),
map(styling => ({styling}))
),
this.getCategories(home.categories).pipe(
defaultIfEmpty([]),
map(categories => ({categories})
),
]),
scan((acc, next) => ({...acc, ...next}), {home, images: null, styling: null, categories: null})
)
);
}
如果要发出所有属性均为startWith({})
的第一个值,可以将merge()
运算符添加到null
运算符。作为消费者的早期价值,他们知道开始阅读其他价值。