我要重写的基于原始承诺的代码:
parentPromise
.then((parentResult) => {
childPromise1
.then(child1Result => child1Handler(parentResult, child1Result));
childPromise2
.then(child1Result => child2Handler(parentResult, child2Result));
childPromise3
.then(child1Result => child3Handler(parentResult, child3Result));
});
在以下情况下,我试图找到一种避免nested subscriptions anti-pattern的方法:
parent$
.pipe(takeUntil(onDestroy$))
.subscribe((parentResult) => {
child1$
.pipe(takeUntil(onDestroy$))
.subscribe(child1Result => child1Handler(parentResult, child1Result));
child2$
.pipe(takeUntil(onDestroy$))
.subscribe(child2Result => child2Handler(parentResult, child2Result));
child3$
.pipe(takeUntil(onDestroy$))
.subscribe(child3Result => child3Handler(parentResult, child3Result));
});
执行此操作的正确“ RxJS方法”是什么?
答案 0 :(得分:1)
这对我来说似乎很奇怪。您每次parentResult
到来时都会为每个孩子创建新的订阅。即使这些最终确实会被销毁(假设实现onDestroy$
是正确的),这似乎也是错误的。
您可能希望为每个孩子使用withLatestFrom(parent$)
和三个单独的管道。
它可能看起来像:
child1$.pipe(takeUntil(globalDeath$), withLatestFrom(parent$)).subscribe(([childResult, parentResult]) => ...)
。不确定我的JS是否正确,目前无法对其进行测试;但关键是:每次parent$
触发时,您都会从child1$
获得最新的结果。请注意,如有必要,可以反转方向(withLatestFrom(child1$)
)。
答案 1 :(得分:0)
您可以:1)通过parent$
传递share
,以及2)使用flatMap
三次,类似:
const sharedParent$ = parent$.pipe(share());
sharedParent$.pipe(
flatMap(parentResult => forkJoin(of(parentResult), child1$)),
takeUntil(onDestroy$)),
.subscribe((results) => child1Handler(...results)); // repeat for all children
(如果有两个以上的子代,则以子流和处理程序作为参数将其提取到函数中是个好主意)。
这是遵循与订阅孩子等待直到parent$
发出的原始行为。如果不需要,可以跳过flatMap
,而只跳过forkJoin
sharedParent$
和子级。
答案 2 :(得分:0)
使用高阶可观察物怎么样?像这样:
const parentReplay$ = parent$.pipe(shareReplay(1));
of(
[child1$, child1Handler],
[child2$, child2Handler],
[child3$, child3Handler]
).pipe(
mergeMap([child$, handler] => parentReplay$.pipe(
mergeMap(parentResult => child$.pipe(
tap(childResult => handler(parentResult, childResult))
)
)
).subscribe();
答案 3 :(得分:0)
如果您使用的是Promises,则相应的Observable仅发出一次,然后完成。
在这种情况下,您可以使用forkJoin
来并行执行子Observable。
所以代码看起来像
parent$.pipe(
takeUntil(onDestroy$),
// wait for parent$ to emit and then move on
// the following forkJoin executes the child observables in parallel and emit when all children complete - the value emitted is an array with the 3 notifications coming from the child observables
concatMap(parentResult => forkJoin(child1$, child2$, child3$)).pipe(
// map returns both the parent and the children notificiations
map(childrenResults => ({parentResult, childrenResults})
)
).subscribe(
({parentResult, childrenResults}) => {
child1Handler(parentResult, childrenResults[0]);
child1Handler(parentResult, childrenResults[1]);
child1Handler(parentResult, childrenResults[2]);
}
)