【问题标题】:Better Observable typescript pattern for if x of Observable<X> else y of Observable<Y>if x of Observable<X> else y of Observable<Y> 更好的 Observable typescript 模式
【发布时间】:2018-12-17 18:04:05
【问题描述】:

我有 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) 的方向是错误的——也许有一种方法可以有条件地从 getY 中提取 Y,而不需要 of(x)。

理想情况下,我会编写一个 getXY 来完成所有这些并返回一个 Observable 可以订阅。


我使用原始示例和卡坦特的答案创建了一个codepen。请注意,当 getX 返回 'x' 时,carant 仍然调用 getY - 这就是我没有将他的答案标记为解决方案的原因。随意分叉并添加您自己的解决方案。

【问题讨论】:

    标签: javascript typescript rxjs observable rxjs6


    【解决方案1】:

    你可以像这样实现你的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&lt;X | Y&gt;,并且实现的必要性稍低。

    使用concat 将确保getY 返回的observable 只有在getX 返回的observable 完成但未发出或发出虚假值时才会被订阅。

    【讨论】:

    • 问题是:getY 总是被调用,所以性能不如原来的。
    • 通常,调用返回 observable 的函数比订阅返回的 observable 更便宜,因为 observable 是惰性的,并且经常执行缓慢的异步任务。在不太可能的情况下,你有一个 getter,你创建一个 observable 是瓶颈,你可以用defer 包装getY。或者,更好的是,您可以在getY 的实现中使用defer,这样它就更懒了。
    • function getY(id) { return defer(() =&gt; /* whatever is your current implementation */); }
    【解决方案2】:

    使用运算符的最简单解决方案是:在 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);
        }
      }));
    };
    

    我已经更新了codepen,包含了这个getXY 函数。以及 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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-27
      • 1970-01-01
      • 2022-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多