baconjs / bacon.js

Functional reactive programming library for TypeScript and JavaScript
https://baconjs.github.io
MIT License
6.47k stars 331 forks source link

[API Addition] bufferUnderCondition #728

Closed semmel closed 5 years ago

semmel commented 5 years ago

What do you think of such a bufferUnderCondition-like function?

It buffers source stream values when the condition is truthy. When the condition is false or the condition has ended, any accumulated values are flushed and subsequent source values are let passed. The resulting stream ends when the both the condition and the source stream have ended. As marble diagrams:

/* c: condition (t -is true, f means false), s: source, r: result
 *
 * time:         200         400         600         800         1000
 * c: t-----------f-----------t-----------f-----------t-----------f<end>
 * s: ---0--1--2----3-----4-----5678-----------9----------10<end>
 * r: -----------0123-----4-------------5678---9-----------------10<end>
 *
 * c: ---t----<end>
 * s: x---x--x--x---x--<end>
 * r: x--------xxx--x--<end>
 *
 * c: ---t--------------<end>
 * s: x---x-y-z<end>
 * r: x-----------------xyz<end>
 */

I could not figure a way to do it simply with the existing API.

My implementation is goes along Bacon.mergeAll(source, condition).withStateMachine. However a PR is blocked because I cannot get the tests running, partly because of #727.

Do you think it is worth pursuing a PR?

raimohanska commented 5 years ago

How about holdWhen?

semmel commented 5 years ago

Hmm. holdWhen seems to be the solution. But I was under the inpression, that as .takeWhile and .takeUntil it would work only once. I now see that it does not, except here I cannot make it work:

var propBus = new Bacon.Bus();
var valve = propBus.toProperty(true);
var stream = Bacon.repeatedly(2000, [0, 1, 2, 3, 4, 5])
.flatMapConcat( v => Bacon.once(v).holdWhen(valve) );
var unsub = stream.onValue(console.log.bind(console));
// ... let some time pass to allow for buffering
propBus.push(false);
// -> 0 1 2 3 4 5 0
propBus.push(true);
// -> 1 2 3 4 it continues to emit values no matter what the valve is !
raimohanska commented 5 years ago

Add a bogus subscriber for the valve property and see if it worx

-juha-

Matthias Seemann notifications@github.com kirjoitti 17.12.2018 kello 16.07:

Hmm. holdWhen seems to be the solution. But I was under the inpression, that as .takeWhile and .takeUntil it would work only once. I now see that it does not, except here I cannot make it work:

var propBus = new Bacon.Bus(); var valve = propBus.toProperty(true); var stream = Bacon.repeatedly(2000, [0, 1, 2, 3, 4, 5]) .flatMapConcat( v => Bacon.once(v).holdWhen(valve) ); var unsub = stream.onValue(console.log.bind(console)); // ... let some time pass to allow for buffering propBus.push(false); // -> 0 1 2 3 4 5 0 propBus.push(true); // -> 1 2 3 4 it continues to emit values no matter what the valve is ! — You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

raimohanska commented 5 years ago

Sorry was on mobile. This might be the problem: https://github.com/baconjs/bacon.js/wiki/FAQ#why-isnt-my-property-updated

semmel commented 5 years ago

Yes, valve needs to be a "hot" (or "eager") observable! It works now. I already have a utility function eagerUntil for that purpose

Bacon.Property.prototype.eagerUntil = function(observable){
    this.takeUntil(observable).onValue(function(){});
    return this;
};

... but I always forget to attach it to my properties! :disappointed_relieved:

Thank you very much!