如何在RxJS中创建一个可观察对象(依次等待2个可观察对象),然后执行操作,然后依次等待那些2个可观察对象

时间:2019-04-11 18:37:26

标签: javascript rxjs

我正在为希望使用RxJS的特定场景而苦苦挣扎:

有两个可观察的对象应按顺序触发以注册一个值:

  1. 表示用户按下按钮的可观察对象

  2. 表示设备返回其下一个值的可观察对象

用户按下按钮后,它应等待设备返回下一个值,然后应捕获并处理该值。之后,它应该再次等待相同的事件顺序。

我发现,如果我使用concat,它可以工作一次,并且在收到按钮动作和设备的值后便完成了可观察对象。

但是,在可观察对象完成之后,我不能再将它们用于后续操作。

我还发现我可以使用zip,这将在两个可观察对象都返回其next()之后触发,但是这样不能保证顺序(在按下按钮后它不会返回下一个值) ,它将发出在此期间发出的值。

这种情况下最佳的解决方案是什么?

import { Observable, Subject, forkJoin } from 'rxjs';
import { concat, repeat, switchMap } from 'rxjs/operators';

let user: Subject<any> = new Subject<any>();
let device: Subject<number> = new Subject<number>();

user.pipe(concat(device)).subscribe(() => {
    console.log("both called");
});


setInterval(() => {
    setTimeout(() => {
        user.complete();
        console.log("user action executed");
    }, 2000);

    setTimeout(() => {
        device.next(new Date().getSeconds());
        console.log("device value sent");
        device.complete();
    }, 5000);
}, 10000);

2 个答案:

答案 0 :(得分:1)

exhaustMap将使您可以收听另一个流,而忽略源流中的后续事件:

const { fromEvent, timer, Subject } = rxjs;
const { exhaustMap, take } = rxjs.operators;

// mock device$ will output every 3 seconds
const device$ = new Subject();
timer(0, 3000).subscribe(device$);
device$.subscribe(console.log); // output device ticking

// listen to button clicks
const btn = document.getElementById('btn');
const click$ = fromEvent(btn, 'click');
click$.pipe(
  // when a button is clicked -- we start listening
  // for the next event on the device$
  // until then we don't react to click$
  exhaustMap(() => device$.pipe(take(1)))
).subscribe(value => {
  console.log('Clicked at ' + value);
});
<script src="https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.min.js"></script>

<button id="btn">Clicker</button>

这里显示了发生的情况

exhaustMap illustration

exhaustMap operator here

希望这会有所帮助

答案 1 :(得分:0)

您可以切换地图并返回另一个可观察的物体。

const { of, fromEvent } = rxjs;
const { switchMap, delay } = rxjs.operators;

fromEvent(document.getElementById('btn'), 'click').pipe(
    switchMap(e => of('some value').pipe(delay(1000)))
  )
  .subscribe(val => { console.log(val) });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>
<button id="btn">Click</button>