我正在为希望使用RxJS的特定场景而苦苦挣扎:
有两个可观察的对象应按顺序触发以注册一个值:
表示用户按下按钮的可观察对象
表示设备返回其下一个值的可观察对象
用户按下按钮后,它应等待设备返回下一个值,然后应捕获并处理该值。之后,它应该再次等待相同的事件顺序。
我发现,如果我使用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);
答案 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>
这里显示了发生的情况
希望这会有所帮助
答案 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>