我有2个可观察值,如果存在,我想从X取值,否则从Y取值。以下对我有用,但我正在寻找更简洁的模式。
import {of} from 'rxjs';
import {map, mergeMap} from 'rxjs/operators';
import {getX, getY} from './getXY';
// getX(id: string): Observable<X>; // gets an X asyncronously
// getY(id: string): Observable<Y>; // gets a Y asyncronously
let id = "abc";
// get an X, or a Y if not X, that matches the id
getX(id).pipe(mergeMap((x: X) => {
if (x) {
return of(x);
} else {
return getY(id).pipe(map((y: Y) => {
if (y) {
return y;
}
}));
}
})).subscribe((xy: X | Y) => { ... }
在我看来,of(x)的方向错误-也许不是mergeMap,有一种方法可以有条件地从getY中提取Y,而无需of(x)。>
理想情况下,我将编写一个getXY来完成所有操作并返回一个Observable
我用原始示例和卡特恩的答案创建了一个codepen。请注意,当getX返回'x'时,Cartant仍然调用getY-这就是为什么我没有将他的答案标记为解决方案的原因。随意分叉并添加自己的解决方案。
答案 0 :(得分:4)
您可以像这样实现getXY
函数:
function getXY(id: string /* or whatever */) {
return concat(
getX(id).pipe(filter(x => Boolean(x))),
getY(id).pipe(filter(y => Boolean(y)))
).pipe(take(1));
}
该函数的返回类型将被推断为Observable<X | Y>
,并且实现的必要性降低了。
使用concat
将确保getY
返回的可观察对象仅在getX
返回的可观察对象完成而没有发出或发出虚假值的情况下被订阅。
答案 1 :(得分:0)
操作员最简单的解决方案是:getX成功时不调用getY:
function getXY(id: string): Observable<X|Y> {
return getX(id).pipe(mergeMap((x: X) => {
if (x) {
return of(x);
} else {
return getY(id);
}
}));
};
我已经使用此getXY函数更新了codepen。以及getXYcartant-以及以下getXYnew:
Observable.create
是另一个可能的答案,因为如果X为空,它不会调用getY:
function getXYnew(id: string): Observable<X|Y> {
return Observable.create(observer => {
getX(id).subscribe(x => {
if (x) {
observer.next(x);
observer.complete();
} else {
getY(id).subscribe(y => {
observer.next(y);
observer.complete();
});
}
});
});
};
但这与其他性能最佳选项一样,创建了另一个Observable。