Sim*_*ver 3 boolean-operations rxjs
如何避免编写疯狂的combineLatest语句来计算简单的布尔逻辑表达式?
例如。这个简单的表达式几乎不适合 stackoverflow 代码控件,如果你不小心重新排序参数,你将很难调试!
this.showPlayButton = combineLatest(this.playPending, this.isReady, this.showOverlay)
.pipe(
map(([playPending, isReady, showOverlay]) => isReady && !playPending && showOverlay),
distinctUntilChanged();
Run Code Online (Sandbox Code Playgroud)
好吧,我很惊讶我找不到一个现有的库,所以我开始收集一些辅助可观察创建函数。
Observable<boolean>帮手这些是“最纯粹”的帮手,既吸收又输出Observable<boolean>。我已经添加distinctUntilChanged()了每一个,这可以防止多次不必要的排放。这是一个非常惰性的运算符,没有更复杂的shareor后果shareReplay(1)- 但重要的是要知道它已被应用。
export const allTrue = (...observables: Array<ObservableInput<boolean>> ) => combineLatest(observables).pipe(map(values => values.every(v => v == true) ), distinctUntilChanged());
export const allFalse = (...observables: Array<ObservableInput<boolean>> ) => combineLatest(observables).pipe(map(values => values.every(v => v == false) ), distinctUntilChanged());
export const anyTrue = (...observables: Array<ObservableInput<boolean>> ) => combineLatest(observables).pipe(map(values => values.find(v => v == true) != undefined ), distinctUntilChanged());
export const anyFalse = (...observables: Array<ObservableInput<boolean>> ) => combineLatest(observables).pipe(map(values => values.find(v => v == false) != undefined), distinctUntilChanged());
export const not = (observable: Observable<boolean> ) => observable.pipe(map(value => !value), distinctUntilChanged());
Run Code Online (Sandbox Code Playgroud)
同一类别中的一些其他“帮助器”,例如ifTruthy或ifFalsy旨在与上述帮助器一起使用(因为它们需要真正的布尔值)。这些当前使用!=与 相对的!==,所以isDefined(of(null))和isDefined(of(undefined))都产生一个trueObservable。也isEqual不会进行深入的比较。
export const isTruthy = <T>(observable: Observable<T>) => observable.pipe(map(obsValue => !!obsValue), distinctUntilChanged());
export const isFalsey = <T>(observable: Observable<T>) => observable.pipe(map(obsValue => !obsValue), distinctUntilChanged());
export const isDefined = <T>(observable: Observable<T>) => observable.pipe(map(obsValue => obsValue != undefined), distinctUntilChanged());
export const isEqual = <T>(observable: Observable<T>, value: T) => observable.pipe(map(obsValue => obsValue == value), distinctUntilChanged());
export const notEqual = <T>(observable: Observable<T>, value: T) => observable.pipe(map(obsValue => obsValue != value), distinctUntilChanged());
Run Code Online (Sandbox Code Playgroud)
还有第三类,相当于iffSQL Server的语句。这些的输出是or (无论你的参数是什么类型)。这就像一个非常简单的 if 语句。 iffAB
export const iff = <A, B>(ifObs: Observable<boolean>, trueValue: A, falseValue: B) => ifObs.pipe(map(value => value ? trueValue : falseValue));
Run Code Online (Sandbox Code Playgroud)
使用 RxJS,可以非常轻松地将它们组合在一起并创建非常可读的组合。我经常在 Angular 组件中使用这些来获取特定于 UI 的属性,并且调试起来要容易得多。下面这些是真实的代码示例,应该是非常不言自明的。
loading$ = not(this.loaded$);
hasSelectedOrder$ = isTruthy(orderId$); // Note: this wouldn't work for something zero
hasSelectedOrder$ = isDefined(orderId$); // uses != undefined
layout$ = iff(deviceType.isDesktop$, 'horizontal', 'vertical');
isMobileOrTablet$: anyTrue(this.isMobile$, this.isTablet);
isTabletOrDesktop$: anyTrue(this.isTablet, this.isDesktop$);
isBusy$ = anyTrue(this.hasBusyTask$, this.busyService.isBusy$);
// very useful for UI (using async pipe)
isAddNewCreditCardSelected$ = isEqual(selectedPaymentMoniker$, 'NEW');
showSavedPayments$ = allTrue(showAvailablePaymentMethods$, hasVault$, not(isAddNewCreditCardSelected$));
showAddCreditCardButton$ = allTrue(showPaymentButtons$, not(showAddCreditCardPanel$), not(showVault$))
showDefaultFooter$ = allTrue(not(this.isWebapp$), this.showDefaultFooter$);
showBusyIndicator$ = allTrue(not(this.pageService.handlesBusyIndicator$), this.busyService.isBusy$) ;
Run Code Online (Sandbox Code Playgroud)
至于原来的问题,就变成了这样:
this.showPlayButton$ = allTrue(this.isReady$, not(this.playPending$), this.showOverlay$)
Run Code Online (Sandbox Code Playgroud)
当我想出新的时,我会添加到这个列表中。这些已经涵盖了我迄今为止遇到的大多数情况。这当然可以制作成一个库,但我现在无法将其形式化以能够做到这一点。如果某些东西已经存在,我很乐意进行比较:-)
| 归档时间: |
|
| 查看次数: |
242 次 |
| 最近记录: |