简体   繁体   中英

How can I pause an RxJS buffered observable based on the values in the buffer as they are evaluated?

I have an observable that wraps a socket.io stream of events from the server (call it source ). Each message from socket.io is emitted on the observable. This observable is filtered and mapped to several subscriptions based on the content of the socket.io messages.

For example:

var filtered = source.filter(function(msg) { return msg.name === 'EventName' });
filtered.subscribe(function handeEventName(msg) { /* do something with msg */ });

Sometimes these subscriptions trigger long animations in my app. I want to pause the source observable when this happens, buffer new events until the animation to plays out, and then resume the observable.

I've got all of this working as expected using pausableBuffered :

var pausable = source.pausableBuffered();
var filtered = pausable.filter(function(msg) { return msg.name === 'EventName' });
filtered.subscribe(function handeEventName(msg) {
    pausable.pause();
    /**
     * do something async, like animation, then when done call
     * pausable.resume();
     */
});

So far so good.

However, let's assume that while the observable is paused, five messages are buffered. The third message is one that needs to pause the stream again. It has a subscription set up to do so. However, as soon as the source observable is un-paused, it immediately empties it's buffer of all five events, all of which get handled and passed to all five subscriptions, at which point the third message's subscription finally pauses the original stream.

I understand why this is happening, but what I really want to have happen instead is:

  1. source is paused
  2. five events are buffered, the third one should pause source when it's subscription is handled.
  3. source is resumed.
  4. events #1 and #2 are handled by their subscriptions,
  5. event #3's subscription pauses the source.
  6. possibly more events could be buffered behind #4 and #5 which are still waiting in the buffer.
  7. event #3's subscription resumes the source after a brief time
  8. events #4 and #5 and any others start to propagate until another event that should pause is emitted by source.

It seems that every way that I use pausableBuffered ends up dumping the entire buffer to all of their subscriptions. How can I achieve what I'm looking for?

You could try a controlled observable. Gives you pretty much complete control. For example:

var source = Rx.Observable.interval(300).take(10);
var controlled = source.controlled();

var sourceSub = source.subscribe(
    function (x) {
        console.log('Next source: ' + x.toString());
    },
    function (err) {
        console.log('Error: ' + err);
    },
    function () {
        console.log('Completed');
    });

var controlledSub = controlled.subscribe(
    function (x) {
        console.log('Next controlled: ' + x.toString());
        if (x === 3) {
            setTimeout(function(){
                controlled.request(1)
            }, 2000)
        } else {
            controlled.request(1);
        }
    },
    function (err) {
        console.log('Error: ' + err);
    },
    function () {
        console.log('Completed');
    });

controlled.request(1);

plunker

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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