如果x的Observable <x>否则y的Observable <y>有更好的Observable打字稿模式

时间:2018-07-10 01:11:37

标签: javascript typescript rxjs observable rxjs6

我有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-这就是为什么我没有将他的答案标记为解决方案的原因。随意分叉并添加自己的解决方案。

2 个答案:

答案 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。