如何在订阅前有条件地使用 Observables 做一些事情?

How to do something conditionally with Observables before subscribe?

我正在尝试实施执行以下步骤的解决方案:

  1. 使用 filter 检查条件是否有效。
  2. 检查Ctrl是否被按下,如果是则执行一些功能。
  3. 最后,再执行一个函数。

我能够使用该代码使其工作:

const click = Observable.fromEvent(element, 'click');
click.filter(() => condition)
     .do((event: MouseEvent) => {
         if (!event.ctrlKey) {
             // maybe do something...
         }
     }).subscribe(() => {
         // aways do something else at end
     });

我想知道是否有更优雅的解决方案可以删除 do 方法中的 if 条件?

不确定我是否理解这个问题,但这里有一种类似的方法可以做到这一点并尽量保持代码整洁:

const click$ = Observable.fromEvent(document, 'click');

// I don't know what's in your condition so I just return true
const condition = () => true;

const fnCtrlIsPressed = () => 'Ctrl is pressed';
const fnCtrlIsNotPressed = () => 'Ctrl is not pressed';

click$
  .map(event => event.ctrlKey)
  .map(isCtrlPressed => isCtrlPressed ?
    fnCtrlIsPressed():
    fnCtrlIsNotPressed())
  .do(console.log)
  .subscribe();

输出将是这样的:

这是一个可用的 Plunkr:https://plnkr.co/edit/VwuXkk0QnVGC4hPCvtOo?p=preview

一个选项是使用一个流来 flatMap,在按下 Ctrl 键的情况下触发适当的操作,这与您的方法没有太大区别。

const condition = () => true;

const clickStreamWithCtrlAction = Observable.fromEvent(element, "click")
  .flatMap(event => event.ctrlKey
    ? Observable.of(event).do(clickWithCtrl => console.log("With ctrl clause"))
    : Observable.of(event)
  )

clickStreamWithCtrlAction
    .filter(condition)
    .subscribe(event => console.log(`Finally clause, ctrlKey: ${event.ctrlKey}`));

为什么不使用管道方法。 是这样的:

import { Observable, tap, filter } from 'rxjs';
const click = Observable.fromEvent(element, 'click')
                   .pipe(filter((valueEmitted) => {
                       //your filter comes here. if everything ok return true;
                   }), tap((valueEmitted) => {
                       //do something before subscribe
                   }));

然后您可以订阅 click observable。

关于点击的更多详细信息:https://www.learnrxjs.io/learn-rxjs/operators/utility/do

有关过滤器的更多详细信息:https://www.learnrxjs.io/learn-rxjs/operators/filtering/filter