简体   繁体   English

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

[英]How to create an observable in RxJS which waits for 2 observables ( in sequence) , then acts , and then waits for those 2 again in sequendce

I'm struggling with a specific scenario for which I was hoping to use RxJS : 我正在尝试使用RxJS的特定场景:

There are two observables which should trigger in sequence for a value to be registered : 有两个可观察值应按顺序触发以注册一个值:

  1. An observable representing a user pressing a button 代表用户按下按钮的可观察对象

  2. An observable representing a device returning it's next value 代表设备返回下一个值的可观察对象

After the user presses the button, it should wait until the device returns it's next value, then this value should be captured and processed. 用户按下按钮后,它应等到设备返回其下一个值后,才应捕获并处理该值。 After that, it should again wait for the same sequence of events. 之后,它应该再次等待相同的事件序列。

I found that it works once if I use concat, and I complete the observables upon receiving the button action and the device's value. 我发现如果使用concat,它可以工作一次,并且在收到按钮动作和设备的值后便完成了可观察项。

However, after the observables complete I can't use them anymore for subsequent actions. 但是,在可观察对象完成之后,我将无法再将它们用于后续操作。

I also found that I could use zip , which would trigger after both observables return their next() , but then the order isn't guaranteed ( it won't return the next value after the button was pressed, it will emit the value that was emitted in the meantime). 我还发现我可以使用zip ,它会在两个可观察对象都返回它们的next()之后触发,但是不能保证顺序(按下按钮后它不会返回下一个值),它将发出同时被发射)。

What would be the best-practice solution for this case ? 在这种情况下,最佳实践解决方案是什么?

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);

exhaustMap will let you listen to another stream while ignoring consequent events from the source stream: 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> 

Heres an illustration of what's going on 这是发生了什么事的例证

exhaustMap图

Play with the exhaustMap operator here . 在此处exhaustMap运算符一起玩。

Hope this helps 希望这可以帮助

You can switchMap and return another observable. 您可以switchMap并返回另一个可观察的对象。

 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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM